soap-nhttp.c

Go to the documentation of this file.
00001 /******************************************************************
00002 *  $Id: soap-nhttp.c,v 1.12 2007/01/01 18:58:05 m0gg Exp $
00003 *
00004 * CSOAP Project:  A SOAP client/server library in C
00005 * Copyright (C) 2003  Ferhat Ayaz
00006 *
00007 * This library is free software; you can redistribute it and/or
00008 * modify it under the terms of the GNU Library General Public
00009 * License as published by the Free Software Foundation; either
00010 * version 2 of the License, or (at your option) any later version.
00011 *
00012 * This library is distributed in the hope that it will be useful,
00013 * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00015 * Library General Public License for more details.
00016 *
00017 * You should have received a copy of the GNU Library General Public
00018 * License along with this library; if not, write to the
00019 * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
00020 * Boston, MA  02111-1307, USA.
00021 * 
00022 * Email: ayaz@jprogrammer.net
00023 ******************************************************************/
00024 #ifdef HAVE_CONFIG_H
00025 #include <config.h>
00026 #endif
00027 
00028 #ifdef HAVE_STDIO_H
00029 #include <stdio.h>
00030 #endif
00031 
00032 #ifdef HAVE_STRING_H
00033 #include <string.h>
00034 #endif
00035 
00036 #ifdef HAVE_ERRNO_H
00037 #include <errno.h>
00038 #endif
00039 
00040 #include <libxml/tree.h>
00041 #include <libxml/uri.h>
00042 #include <libxml/xpath.h>
00043 
00044 #include <nanohttp/nanohttp-error.h>
00045 #include <nanohttp/nanohttp-common.h>
00046 #include <nanohttp/nanohttp-logging.h>
00047 #include <nanohttp/nanohttp-stream.h>
00048 #include <nanohttp/nanohttp-request.h>
00049 #include <nanohttp/nanohttp-response.h>
00050 
00051 #include <nanohttp/nanohttp-client.h>
00052 #include <nanohttp/nanohttp-server.h>
00053 
00054 #include "soap-fault.h"
00055 #include "soap-env.h"
00056 #include "soap-ctx.h"
00057 #include "soap-service.h"
00058 #include "soap-client.h"
00059 #include "soap-transport.h"
00060 #include "soap-addressing.h"
00061 #include "soap-xml.h"
00062 #include "soap-router.h"
00063 #include "soap-server.h"
00064 
00065 #include "soap-admin.h"
00066 #include "soap-wsil.h"
00067 
00068 #include "soap-nhttp.h"
00069 
00070 static herror_t
00071 _soap_nhttp_send_document(httpd_conn_t *conn, xmlDocPtr doc)
00072 {
00073   char length[16];
00074   xmlChar *buf;
00075   int size;
00076 
00077   xmlDocDumpMemory(doc, &buf, &size);
00078 
00079   sprintf(length, "%d", size);
00080   httpd_set_header(conn, HEADER_CONTENT_TYPE, "text/xml");
00081   httpd_set_header(conn, HEADER_CONTENT_LENGTH, length);
00082   httpd_send_header(conn, 200, HTTP_STATUS_200_REASON_PHRASE);
00083 
00084   http_output_stream_write(conn->out, buf, size);
00085 
00086   xmlFree(buf);
00087 
00088   return H_OK;
00089 }
00090 
00091 static herror_t
00092 _soap_nhttp_send_fault(httpd_conn_t *conn, const char *message)
00093 {
00094   xmlDocPtr doc;
00095   herror_t ret;
00096 
00097   doc = soap_fault_build(SOAP_FAULT_SENDER, message, soap_transport_get_name(), NULL);
00098   ret = _soap_nhttp_send_document(conn, doc);
00099   xmlFreeDoc(doc);
00100 
00101   return ret;
00102 }
00103 
00104 static int
00105 _soap_nhttp_xml_io_read(void *ctx, char *buffer, int len)
00106 {
00107   int ret;
00108   struct http_input_stream_t *in;
00109  
00110   in = (struct http_input_stream_t *)ctx;
00111   if (!http_input_stream_is_ready(in))
00112     return 0;
00113 
00114   if ((ret = http_input_stream_read(in, buffer, len)) == -1)
00115     return 0;
00116 
00117   return ret;
00118 }
00119 
00120 static int
00121 _soap_nhttp_xml_io_close(void *ctx)
00122 {
00123   /* nothing */
00124   return 0;
00125 }
00126 
00127 static herror_t
00128 _soap_nhttp_env_new_from_stream(struct http_input_stream_t *in, struct SoapEnv **out)
00129 {
00130   xmlDocPtr doc;
00131 
00132   doc = xmlReadIO(_soap_nhttp_xml_io_read, _soap_nhttp_xml_io_close, in, "", NULL, 0);
00133   if (in->err != H_OK)
00134     return in->err;
00135 
00136   if (doc == NULL)
00137     return herror_new("_soap_nhttp_env_new_from_stream", XML_ERROR_PARSE, "Trying to parse invalid XML");
00138 
00139   return soap_env_new_from_doc(doc, out);
00140 }
00141 
00142 static void
00143 soap_nhttp_process(httpd_conn_t * conn, struct hrequest_t * req)
00144 {
00145   char *action;
00146   struct SoapEnv *env;
00147   struct SoapCtx *request;
00148   struct SoapCtx *response;
00149   herror_t err;
00150 
00151   if (req->method == HTTP_REQUEST_GET)
00152   {
00153     struct SoapRouter *router;
00154 
00155     router = soap_server_find_router(req->path);
00156     if (router && router->description)
00157     {
00158       _soap_nhttp_send_document(conn, router->description);
00159       return;
00160     }
00161   }
00162 
00163   if (req->method != HTTP_REQUEST_POST)
00164   {
00165     httpd_send_not_implemented(conn, "I only speak with 'POST' method.");
00166     return;
00167   }
00168 
00169   if ((err = _soap_nhttp_env_new_from_stream(req->in, &env)) != H_OK)
00170   {
00171     _soap_nhttp_send_fault(conn, herror_message(err));
00172     herror_release(err);
00173     return;
00174   }
00175 
00176   if (env == NULL)
00177   {
00178     _soap_nhttp_send_fault(conn, "Cannot receive POST data!");
00179     return;
00180   }
00181 
00182   request = soap_ctx_new(env);
00183 
00184   if ((action = hpairnode_get_ignore_case(req->header, SOAP_NHTTP_SOAP_ACTION)))
00185   {
00186     soap_addressing_set_action_string(env, action);
00187   }
00188 
00189   /* xmlDocFormatDump(stdout, ctx->env->root->doc, 1); */
00190 
00191   soap_ctx_add_files(request, req->attachments);
00192 
00193   /* only local part is interesting...
00194   soap_addressing_set_to_address_string(ctx->env, req->path); */
00195 
00196   soap_transport_process(request, &response);
00197 
00198   _soap_nhttp_send_document(conn, response->env->root->doc);
00199 
00200   soap_ctx_free(response);
00201 
00202   soap_ctx_free(request);
00203 
00204   return;
00205 }
00206 
00207 herror_t
00208 soap_nhttp_server_init_args(int argc, char **argv)
00209 {
00210   herror_t err;
00211  
00212   if ((err = httpd_init(argc, argv)) != H_OK)
00213   {
00214     log_error2("httpd_init failed (%s)", herror_message(err));
00215     return err;
00216   }
00217 
00218   if ((err = soap_wsil_init_args(argc, argv)) != H_OK)
00219   {
00220     log_error2("soap_wsil_init_args failed (%s)", herror_message(err));
00221     return err;
00222   }
00223 
00224   if ((err = soap_admin_init_args(argc, argv)) != H_OK)
00225   {
00226     log_error2("soap_admin_init_args failed (%s)", herror_message(err));
00227     return err;
00228   }
00229 
00230   return H_OK;
00231 }
00232 
00233 static herror_t
00234 _soap_nhttp_client_build_result(hresponse_t * res, struct SoapEnv ** env)
00235 {
00236   log_verbose2("Building result (%p)", res);
00237 
00238   if (res == NULL)
00239     return herror_new("_soap_client_build_result",
00240                       GENERAL_INVALID_PARAM, "hresponse_t is NULL");
00241 
00242   if (res->in == NULL)
00243     return herror_new("_soap_client_build_result",
00244                       GENERAL_INVALID_PARAM, "Empty response from server");
00245 
00246   if (res->errcode != 200)
00247     return herror_new("_soap_client_build_result",
00248                       GENERAL_INVALID_PARAM, "HTTP code is not OK (%i)", res->errcode);
00249 
00250   return _soap_nhttp_env_new_from_stream(res->in, env);
00251 }
00252 
00253 static herror_t
00254 _soap_nhttp_client_invoke(void *unused, struct SoapCtx *request, struct SoapCtx **response)
00255 {
00256   herror_t status;
00257 
00258   /* Buffer variables */
00259   xmlChar *buffer;
00260   int size;
00261   char tmp[15];
00262   char *action;
00263   char *url;
00264   struct SoapEnv *res_env;
00265 
00266   /* Transport variables */
00267   httpc_conn_t *conn;
00268   hresponse_t *res;
00269 
00270   /* multipart/related start id */
00271   char start_id[150];
00272   static int counter = 1;
00273   struct part_t *part;
00274 
00275   /* for copy attachments */
00276   char href[MAX_HREF_SIZE];
00277 
00278   /* log_verbose1("nanohttp client"); */
00279 
00280   xmlDocDumpMemory(request->env->root->doc, &buffer, &size);
00281 
00282   /* xmlDocFormatDump(stdout, request->env->root->doc, 1); */
00283 
00284   /* Transport via HTTP */
00285   if (!(conn = httpc_new()))
00286   {
00287     return herror_new("soap_client_invoke", SOAP_ERROR_CLIENT_INIT, "Unable to create HTTP client!");
00288   }
00289 
00290   if ((action = soap_addressing_get_action_string(request->env)))
00291     httpc_set_header(conn, SOAP_NHTTP_SOAP_ACTION, action);
00292   else
00293     httpc_set_header(conn, SOAP_NHTTP_SOAP_ACTION, "");
00294   log_verbose2("action is \"%s\"", action);
00295   free(action);
00296 
00297   httpc_set_header(conn, HEADER_CONNECTION, "Close");
00298 
00299   if (!(url = soap_addressing_get_to_address_string(request->env)))
00300     return herror_new("soap_nhttp_client_invoke", 0, "Missing client URL");
00301   log_verbose2("url is \"%s\"", url);
00302 
00303   if (!request->attachments)
00304   {
00305     /* content-type is always 'text/xml' */
00306     httpc_set_header(conn, HEADER_CONTENT_TYPE, "text/xml");
00307 
00308     sprintf(tmp, "%d", size);
00309     httpc_set_header(conn, HEADER_CONTENT_LENGTH, tmp);
00310 
00311     if ((status = httpc_post_begin(conn, url)) != H_OK)
00312     {
00313       httpc_close_free(conn);
00314       xmlFree(buffer);
00315       return status;
00316     }
00317 
00318     if ((status = http_output_stream_write(conn->out, buffer, size)) != H_OK)
00319     {
00320       httpc_close_free(conn);
00321       xmlFree(buffer);
00322       return status;
00323     }
00324 
00325     if ((status = httpc_post_end(conn, &res)) != H_OK)
00326     {
00327       httpc_close_free(conn);
00328       xmlFree(buffer);
00329       return status;
00330     }
00331   }
00332   else
00333   {
00334     httpc_set_header(conn, HEADER_TRANSFER_ENCODING, TRANSFER_ENCODING_CHUNKED);
00335 
00336     sprintf(start_id, "289247829121218%d", counter++);
00337     if ((status = httpc_mime_begin(conn, url, start_id, "", "text/xml")) != H_OK)
00338     {
00339       httpc_close_free(conn);
00340       xmlFree(buffer);
00341       return status;
00342     }
00343 
00344     if ((status = httpc_mime_next(conn, start_id, "text/xml", "binary")) != H_OK)
00345     {
00346       httpc_close_free(conn);
00347       xmlFree(buffer);
00348       return status;
00349     }
00350 
00351     if ((status = http_output_stream_write(conn->out, buffer, size)) != H_OK)
00352     {
00353       httpc_close_free(conn);
00354       xmlFree(buffer);
00355       return status;
00356     }
00357 
00358     for (part=request->attachments->parts; part; part=part->next)
00359     {
00360       if ((status = httpc_mime_send_file(conn, part->id, part->content_type, part->transfer_encoding, part->filename)) != H_OK)
00361       {
00362         log_error2("httpc_mime_send_file failed (%s)", herror_message(status));
00363         httpc_close_free(conn);
00364         xmlFree(buffer);
00365         return status;
00366       }
00367     }
00368     
00369     if ((status = httpc_mime_end(conn, &res)) != H_OK)
00370     {
00371       httpc_close_free(conn);
00372       xmlFree(buffer);
00373       return status;
00374     }
00375   }
00376 
00377   xmlFree(buffer);
00378   free(url);
00379 
00380   if ((status = _soap_nhttp_client_build_result(res, &res_env)) != H_OK)
00381   {
00382     hresponse_free(res);
00383     httpc_close_free(conn);
00384     return status;
00385   }
00386 
00387   *response = soap_ctx_new(res_env);
00388   /* soap_ctx_add_files(*response, res->attachments) */
00389 
00390   if (res->attachments != NULL)
00391   {
00392     part = res->attachments->parts;
00393     while (part)
00394     {
00395       soap_ctx_add_file(*response, part->filename, part->content_type, href);
00396       part->deleteOnExit = 0;
00397       part = part->next;
00398     }
00399   }
00400 
00401   hresponse_free(res);
00402   httpc_close_free(conn);
00403 
00404   /* log_verbose1("done"); */
00405 
00406   return H_OK;
00407 }
00408 
00409 herror_t
00410 soap_nhttp_client_init_args(int argc, char **argv)
00411 {
00412   herror_t status;
00413 
00414   if ((status = httpc_init(argc, argv)) != H_OK)
00415   {
00416     log_error2("httpc_init failed (%s)", herror_message(status));
00417     return status;
00418   }
00419 
00420   soap_transport_add("https", NULL, _soap_nhttp_client_invoke);
00421   soap_transport_add("http", NULL, _soap_nhttp_client_invoke);
00422 
00423   return H_OK;
00424 }
00425 
00426 herror_t
00427 soap_nhttp_register(const char *context)
00428 {
00429   herror_t status;
00430 
00431   if ((status = httpd_register(context, soap_nhttp_process)) != H_OK)
00432   {
00433     log_error2("httpd_register_secure failed (%s)", herror_message(status));
00434     return status;
00435   }
00436 
00437   return H_OK;
00438 }
00439 
00440 herror_t
00441 soap_nhttp_server_run(void)
00442 {
00443   return httpd_run();
00444 }
00445 
00446 void
00447 soap_nhttp_server_destroy(void)
00448 {
00449   httpd_destroy();
00450 
00451   return;
00452 }
00453 
00454 void
00455 soap_nhttp_client_destroy(void)
00456 {
00457   httpc_destroy();
00458 
00459   return;
00460 }
00461 
00462 short
00463 soap_nhttp_get_port(void)
00464 {
00465   return httpd_get_port();
00466 }
00467 
00468 const char *
00469 soap_nhttp_get_protocol(void)
00470 {
00471   return httpd_get_protocol();
00472 }

Generated on Thu Jan 25 23:36:03 2007 for csoap by  doxygen 1.4.6