00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
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
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
00190
00191 soap_ctx_add_files(request, req->attachments);
00192
00193
00194
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
00259 xmlChar *buffer;
00260 int size;
00261 char tmp[15];
00262 char *action;
00263 char *url;
00264 struct SoapEnv *res_env;
00265
00266
00267 httpc_conn_t *conn;
00268 hresponse_t *res;
00269
00270
00271 char start_id[150];
00272 static int counter = 1;
00273 struct part_t *part;
00274
00275
00276 char href[MAX_HREF_SIZE];
00277
00278
00279
00280 xmlDocDumpMemory(request->env->root->doc, &buffer, &size);
00281
00282
00283
00284
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
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
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
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 }