00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include <glib.h>
00023 #include <libsyncml/syncml.h>
00024 #include <libsyncml/syncml_internals.h>
00025
00026 #include <libsyncml/sml_error_internals.h>
00027 #include <libsyncml/sml_transport_internals.h>
00028
00029 #include "http_server_internals.h"
00030
00031 #ifdef HAVE_LIBSOUP22
00032 static void smlTransportHttpServerCallback(
00033 SoupServerContext *context,
00034 SoupMessage *msg,
00035 gpointer data)
00036 {
00037 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, context, msg, data);
00038 SmlMimeType mimetype = SML_MIMETYPE_UNKNOWN;
00039 smlAssert(data);
00040 SmlTransportHttpServerEnv *env = data;
00041 SmlLinkHttpServerEnv *linkenv = NULL;
00042 SmlLink *link_ = NULL;
00043 SmlError *error = NULL;
00044
00045 char *path = soup_uri_to_string (soup_message_get_uri(msg), TRUE);
00046 smlTrace(TRACE_INTERNAL, "%s: %s %s HTTP/1.%d",
00047 __func__, VA_STRING(msg->method), VA_STRING(path), soup_message_get_http_version(msg));
00048
00049 if (g_strcasecmp(path, env->url)) {
00050
00051 smlSafeCFree(&path);
00052 path = soup_uri_to_string (soup_message_get_uri(msg), FALSE);
00053 link_ = g_hash_table_lookup(env->uriToLink, path);
00054 if (!link_)
00055 {
00056
00057
00058
00059
00060
00061
00062 smlErrorSet(&error, SML_ERROR_INTERNAL_FILE_NOT_FOUND,
00063 "Not Found (%s).", path);
00064 soup_message_set_status(msg, SOUP_STATUS_NOT_FOUND);
00065 smlSafeCFree(&path);
00066 goto error;
00067 }
00068 smlLinkRef(link_);
00069 }
00070 smlSafeCFree(&path);
00071
00072 if (soup_message_get_http_version(msg) != 1) {
00073 smlErrorSet(&error, SML_ERROR_NOT_IMPLEMENTED, "Wrong http version");
00074 soup_message_set_status(msg, SOUP_STATUS_NOT_IMPLEMENTED);
00075 goto error;
00076 }
00077
00078 if (soup_method_get_id(msg->method) != SOUP_METHOD_ID_POST) {
00079 smlErrorSet(&error, SML_ERROR_NOT_IMPLEMENTED, "Wrong method");
00080 soup_message_set_status(msg, SOUP_STATUS_NOT_IMPLEMENTED);
00081 goto error;
00082 }
00083
00084 const char *header = soup_message_get_header(msg->request_headers, "Content-Type");
00085 if (header && !g_strncasecmp(header, SML_ELEMENT_XML, strlen(SML_ELEMENT_XML)))
00086 mimetype = SML_MIMETYPE_XML;
00087 else if(header && !g_strncasecmp(header, SML_ELEMENT_WBXML, strlen(SML_ELEMENT_WBXML)))
00088 mimetype = SML_MIMETYPE_WBXML;
00089 else if(header && !g_strncasecmp(header, SML_ELEMENT_SAN, strlen(SML_ELEMENT_SAN)))
00090 mimetype = SML_MIMETYPE_SAN;
00091 else if (header) {
00092 smlErrorSet(&error, SML_ERROR_GENERIC, "Unknown mimetype");
00093 soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST);
00094 goto error;
00095 } else {
00096 smlErrorSet(&error, SML_ERROR_GENERIC, "Faulty mimetype");
00097 soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST);
00098 goto error;
00099 }
00100
00101
00102 if (!link_)
00103 {
00104
00105
00106
00107
00108
00109 linkenv = smlTryMalloc0(sizeof(SmlLinkHttpServerEnv), &error);
00110 if (!linkenv)
00111 goto error;
00112 linkenv->env = env;
00113 link_ = smlLinkNew(env->tsp, linkenv, &error);
00114 if (!link_)
00115 goto error;
00116 linkenv->msg = msg;
00117
00118 linkenv->link = link_;
00119 smlLinkRef(linkenv->link);
00120
00121
00122
00123 smlTransportReceiveEvent(env->tsp, link_, SML_TRANSPORT_EVENT_CONNECT_DONE, NULL, NULL);
00124
00125 } else {
00126 linkenv = link_->link_data;
00127 if (linkenv->msg)
00128 smlTrace(TRACE_INTERNAL,
00129 "%s: WARNING: ResponseURI should not be in use - test mode.",
00130 __func__);
00131 linkenv->msg = msg;
00132 }
00133
00134 smlTrace(TRACE_INTERNAL, "%s: The message length is %i.", __func__, msg->request.length);
00135
00136
00137
00138
00139
00140
00141
00142
00143
00144 char *body = smlTryMalloc0(msg->request.length + 1, &error);
00145 if (!body)
00146 goto error;
00147 memcpy(body, msg->request.body, msg->request.length);
00148
00149 SmlTransportData *tspdata = smlTransportDataNew(body, msg->request.length, mimetype, TRUE, &error);
00150 body = NULL;
00151 if (!tspdata)
00152 goto error_unref_msg;
00153
00154 smlTransportReceiveEvent(env->tsp, link_, SML_TRANSPORT_EVENT_DATA, tspdata, NULL);
00155
00156 smlLinkDeref(link_);
00157 smlTransportDataDeref(tspdata);
00158
00159 soup_message_io_pause(msg);
00160
00161 smlTrace(TRACE_EXIT, "%s", __func__);
00162 return;
00163
00164 error_unref_msg:
00165 link_->link_data = NULL;
00166 smlLinkDeref(link_);
00167 linkenv->msg = NULL;
00168 smlSafeFree((gpointer *) &linkenv);
00169 error:
00170 soup_server_message_set_encoding (SOUP_SERVER_MESSAGE (msg), SOUP_TRANSFER_CONTENT_LENGTH);
00171 soup_message_io_unpause(msg);
00172 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(&error));
00173 smlErrorDeref(&error);
00174 }
00175
00176 #else
00177
00178 static void smlTransportHttpServerCallback(
00179 SoupServer *server,
00180 SoupMessage *msg,
00181 const char *path,
00182 GHashTable *query,
00183 SoupClientContext *client,
00184 gpointer data)
00185 {
00186 smlTrace(TRACE_ENTRY, "%s(%p, %p, %s, %p, %p, %p)", __func__, server, msg, VA_STRING(path), query, client, data);
00187 SmlMimeType mimetype = SML_MIMETYPE_UNKNOWN;
00188 smlAssert(data);
00189 SmlTransportHttpServerEnv *env = data;
00190 SmlLinkHttpServerEnv *linkenv = NULL;
00191 SmlLink *link_ = NULL;
00192 SmlError *error = NULL;
00193
00194 smlTrace(TRACE_INTERNAL, "%s: %s %s HTTP/1.%d",
00195 __func__, VA_STRING(msg->method), VA_STRING(path), soup_message_get_http_version(msg));
00196
00197 if (msg->method != SOUP_METHOD_POST) {
00198 smlErrorSet(&error, SML_ERROR_NOT_IMPLEMENTED, "Wrong method");
00199 soup_message_set_status(msg, SOUP_STATUS_NOT_IMPLEMENTED);
00200 goto error;
00201 }
00202
00203 if (g_strcasecmp(path, env->url)) {
00204
00205 char *fullpath = soup_uri_to_string (soup_message_get_uri(msg), FALSE);
00206 link_ = g_hash_table_lookup(env->uriToLink, fullpath);
00207 if (!link_)
00208 {
00209
00210
00211
00212
00213
00214
00215 smlErrorSet(&error, SML_ERROR_INTERNAL_FILE_NOT_FOUND,
00216 "Not Found (%s).", fullpath);
00217 soup_message_set_status(msg, SOUP_STATUS_NOT_FOUND);
00218 smlSafeCFree(&fullpath);
00219 goto error;
00220 }
00221 smlLinkRef(link_);
00222 smlSafeCFree(&fullpath);
00223 }
00224
00225 const char *header = soup_message_headers_get(msg->request_headers, "Content-Type");
00226 if (header && !g_strncasecmp(header, SML_ELEMENT_XML, strlen(SML_ELEMENT_XML)))
00227 mimetype = SML_MIMETYPE_XML;
00228 else if(header && !g_strncasecmp(header, SML_ELEMENT_WBXML, strlen(SML_ELEMENT_WBXML)))
00229 mimetype = SML_MIMETYPE_WBXML;
00230 else if(header && !g_strncasecmp(header, SML_ELEMENT_SAN, strlen(SML_ELEMENT_SAN)))
00231 mimetype = SML_MIMETYPE_SAN;
00232 else if (header) {
00233 smlErrorSet(&error, SML_ERROR_GENERIC, "Unknown mimetype");
00234 soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST);
00235 goto error;
00236 } else {
00237 smlErrorSet(&error, SML_ERROR_GENERIC, "Faulty mimetype");
00238 soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST);
00239 goto error;
00240 }
00241
00242
00243 if (!link_)
00244 {
00245
00246
00247
00248
00249
00250 linkenv = smlTryMalloc0(sizeof(SmlLinkHttpServerEnv), &error);
00251 if (!linkenv)
00252 goto error;
00253 linkenv->env = env;
00254 link_ = smlLinkNew(env->tsp, linkenv, &error);
00255 if (!link_)
00256 goto error;
00257 linkenv->msg = msg;
00258
00259 linkenv->link = link_;
00260 smlLinkRef(linkenv->link);
00261
00262
00263
00264 smlTransportReceiveEvent(env->tsp, link_, SML_TRANSPORT_EVENT_CONNECT_DONE, NULL, NULL);
00265 } else {
00266 linkenv = link_->link_data;
00267 if (linkenv->msg)
00268 smlTrace(TRACE_INTERNAL,
00269 "%s: WARNING: ResponseURI should not be in use - test mode.",
00270 __func__);
00271 linkenv->msg = msg;
00272 }
00273
00274 if (msg->request_body) {
00275 smlTrace(TRACE_INTERNAL, "%s: The message length is %i.",
00276 __func__, msg->request_body->length);
00277 } else {
00278 smlTrace(TRACE_INTERNAL, "%s: The message has no request body.", __func__);
00279 }
00280
00281
00282
00283
00284
00285
00286
00287
00288
00289 char *body = smlTryMalloc0(msg->request_body->length + 1, &error);
00290 if (!body)
00291 goto error;
00292 memcpy(body, msg->request_body->data, msg->request_body->length);
00293
00294 SmlTransportData *tspdata = smlTransportDataNew(body, msg->request_body->length, mimetype, TRUE, &error);
00295 body = NULL;
00296 if (!tspdata)
00297 goto error_unref_msg;
00298
00299 smlTransportReceiveEvent(env->tsp, link_, SML_TRANSPORT_EVENT_DATA, tspdata, NULL);
00300 smlLinkDeref(link_);
00301
00302
00303
00304 smlTransportDataDeref(tspdata);
00305
00306 soup_server_pause_message(server, msg);
00307
00308 smlTrace(TRACE_EXIT, "%s", __func__);
00309 return;
00310
00311 error_unref_msg:
00312 smlLinkDeref(link_);
00313 error:
00314 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(&error));
00315 smlErrorDeref(&error);
00316 }
00317
00318 #endif
00319
00320 static SmlBool smlTransportHttpServerSetConfigOption(
00321 SmlTransport *tsp,
00322 const char *name,
00323 const char *value,
00324 SmlError **error)
00325 {
00326 smlTrace(TRACE_ENTRY, "%s(%p, %s, %s, %p)", __func__, tsp, VA_STRING(name), VA_STRING(value), error);
00327 CHECK_ERROR_REF
00328 smlAssert(tsp);
00329 smlAssert(tsp->transport_data);
00330 SmlTransportHttpServerEnv *env = tsp->transport_data;
00331
00332 if (!strcmp(name, SML_TRANSPORT_CONFIG_PORT)) {
00333 env->port = atoi(value);
00334 if (!(env->port > 0 && env->port < 65535)) {
00335 smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION, "specified port was wrong");
00336 smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
00337 return FALSE;
00338 }
00339 smlTrace(TRACE_INTERNAL, "%s: Port %i detected", __func__, env->port);
00340 } else if (!strcmp(name, SML_TRANSPORT_CONFIG_URL)) {
00341 env->url = g_strdup(value);
00342 smlTrace(TRACE_INTERNAL, "%s: URL %s detected", __func__, VA_STRING(env->url));
00343 } else if (!strcmp(name, SML_TRANSPORT_CONFIG_SSL_KEY)) {
00344 env->ssl_key = g_strdup(value);
00345 smlTrace(TRACE_INTERNAL, "%s: SSL key %s detected", __func__, VA_STRING(env->ssl_key));
00346 } else if (!strcmp(name, SML_TRANSPORT_CONFIG_SSL_SERVER_CERT)) {
00347 env->ssl_cert = g_strdup(value);
00348 smlTrace(TRACE_INTERNAL, "%s: SSL server certificate %s detected", __func__, VA_STRING(env->ssl_cert));
00349 } else {
00350 smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION, "Unknown parameter %s found.", name);
00351 smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
00352 return FALSE;
00353 }
00354
00355 smlTrace(TRACE_EXIT, "%s", __func__);
00356 return TRUE;
00357 }
00358
00359 static SmlBool smlTransportHttpServerInit(SmlTransport *tsp, SmlError **error)
00360 {
00361 smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, tsp, error);
00362 CHECK_ERROR_REF
00363 smlAssert(tsp);
00364 smlAssert(tsp->context);
00365 smlAssert(tsp->transport_data);
00366 SmlTransportHttpServerEnv *env = tsp->transport_data;
00367
00368 if (!env->port)
00369 {
00370 smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION,
00371 "The HTTP server needs a port where it has to run.");
00372 goto error_free_env;
00373 }
00374
00375 if (!env->url)
00376 {
00377
00378 env->url = g_strdup("/");
00379 }
00380
00381 smlTrace(TRACE_INTERNAL, "%s: config: port %i, url %s", __func__, env->port, VA_STRING(env->url));
00382 smlTrace(TRACE_INTERNAL, "%s: http server uses context %p.", __func__, tsp->context);
00383
00384 if(!env->ssl_key || !env->ssl_cert) {
00385 env->server = soup_server_new(
00386 SOUP_SERVER_ASYNC_CONTEXT, tsp->context,
00387 SOUP_SERVER_PORT, env->port,
00388 NULL);
00389 } else {
00390 env->server = soup_server_new(
00391 SOUP_SERVER_ASYNC_CONTEXT, tsp->context,
00392 SOUP_SERVER_PORT, env->port,
00393 SOUP_SERVER_SSL_CERT_FILE, env->ssl_cert,
00394 SOUP_SERVER_SSL_KEY_FILE, env->ssl_key,
00395 NULL);
00396 }
00397 if (!env->server) {
00398 smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION, "Unable to spawn server");
00399 goto error_free_env;
00400 }
00401
00402 #ifdef HAVE_LIBSOUP22
00403 soup_server_add_handler(env->server, NULL, NULL, smlTransportHttpServerCallback, NULL, env);
00404 #else
00405 soup_server_add_handler(env->server, NULL, smlTransportHttpServerCallback, env, NULL);
00406 #endif
00407
00408 soup_server_run_async(env->server);
00409
00410 smlTrace(TRACE_EXIT, "%s", __func__);
00411 return TRUE;
00412
00413 error_free_env:
00414 if (env->url)
00415 smlSafeCFree(&(env->url));
00416
00417 smlSafeFree((gpointer *)&env);
00418
00419 smlTrace(TRACE_EXIT_ERROR, "%s: %s", __func__, smlErrorPrint(error));
00420 return FALSE;
00421 }
00422
00423 static void smlTransportHttpServerDisconnect(void *data, void *linkdata)
00424 {
00425 smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, data, linkdata);
00426 smlAssert(linkdata);
00427 SmlTransportHttpServerEnv *env = data;
00428 SmlLinkHttpServerEnv *linkenv = linkdata;
00429
00430
00431 smlTrace(TRACE_INTERNAL, "%s: remove link from session/uri cache", __func__);
00432 if (linkenv->session)
00433 {
00434 char *uri = g_hash_table_lookup(linkenv->env->sessionToUri, linkenv->session);
00435 g_hash_table_remove(linkenv->env->sessionToUri, linkenv->session);
00436 if (uri)
00437 smlSafeCFree(&uri);
00438
00439
00440
00441 smlSessionUnref(linkenv->session);
00442 smlSessionUnref(linkenv->session);
00443 linkenv->session = NULL;
00444 }
00445
00446
00447 SmlLink *link_ = NULL;
00448 smlTrace(TRACE_INTERNAL, "%s: remove link from uri/link cache", __func__);
00449 if (linkenv->url)
00450 {
00451 link_ = g_hash_table_lookup(linkenv->env->uriToLink, linkenv->url);
00452 g_hash_table_remove(linkenv->env->uriToLink, linkenv->url);
00453 smlLinkDeref(link_);
00454 smlSafeCFree(&(linkenv->url));
00455 }
00456
00457
00458 link_ = linkenv->link;
00459
00460
00461 if (linkenv->msg)
00462 {
00463 smlTrace(TRACE_INTERNAL, "%s: close open message/connection", __func__);
00464 soup_message_set_status (linkenv->msg, SOUP_STATUS_SERVICE_UNAVAILABLE);
00465 #ifdef HAVE_LIBSOUP22
00466
00467
00468
00469 soup_message_io_unpause(linkenv->msg);
00470 #else
00471 soup_server_unpause_message(linkenv->env->server, linkenv->msg);
00472 #endif
00473 linkenv->msg = NULL;
00474 }
00475
00476
00477 smlTrace(TRACE_INTERNAL, "%s: free memory", __func__);
00478 linkenv->env = NULL;
00479 link_->link_data = NULL;
00480 smlSafeFree((gpointer *)&linkenv);
00481
00482 smlTrace(TRACE_INTERNAL, "%s: signal and unref link", __func__);
00483 smlTransportReceiveEvent(env->tsp, link_, SML_TRANSPORT_EVENT_DISCONNECT_DONE, NULL, NULL);
00484 smlLinkDeref(link_);
00485 smlTrace(TRACE_EXIT, "%s", __func__);
00486 }
00487
00488 static void smlTransportHttpServerFreeResponseURI(gpointer key)
00489 {
00490 smlTrace(TRACE_ENTRY, "%s(%p)", __func__, key);
00491 smlSafeCFree((char **)&key);
00492 smlTrace(TRACE_EXIT, "%s", __func__);
00493 }
00494
00495 static gboolean smlTransportHttpServerFreeUriToLink(
00496 gpointer key,
00497 gpointer value,
00498 gpointer user_data)
00499 {
00500 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, key, value, user_data);
00501
00502 char *uri = key;
00503 SmlLink *link_ = value;
00504
00505 smlLinkDeref(link_);
00506 smlSafeCFree(&uri);
00507
00508 smlTrace(TRACE_EXIT, "%s", __func__);
00509 return TRUE;
00510 }
00511
00512 static gboolean smlTransportHttpServerFreeSessionToUri(
00513 gpointer key,
00514 gpointer value,
00515 gpointer user_data)
00516 {
00517 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, key, value, user_data);
00518
00519 SmlSession *session = key;
00520 char *uri = value;
00521
00522 smlSafeCFree(&uri);
00523 smlSessionUnref(session);
00524
00525 smlTrace(TRACE_EXIT, "%s", __func__);
00526 return TRUE;
00527 }
00528
00529 static SmlBool smlTransportHttpServerCleanupSocket(
00530 gpointer data,
00531 SmlError **error)
00532 {
00533 smlTrace(TRACE_ENTRY, "%s", __func__);
00534 CHECK_ERROR_REF
00535 smlAssert(data);
00536
00537 SoupServer *server = data;
00538
00539 soup_server_quit(server);
00540 g_object_unref(server);
00541
00542 smlTrace(TRACE_EXIT, "%s", __func__);
00543 return TRUE;
00544 }
00545
00546 static SmlBool smlTransportHttpServerFinalize(void *data, SmlError **error)
00547 {
00548 smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, data, error);
00549 CHECK_ERROR_REF
00550 smlAssert(data);
00551 SmlTransportHttpServerEnv *env = data;
00552
00553 smlAssert(env->tsp);
00554
00555 if (env->server) {
00556
00557
00558
00559
00560 if (!smlThreadCallFunction(
00561 env->tsp->thread,
00562 smlTransportHttpServerCleanupSocket,
00563 env->server,
00564 error))
00565 goto error;
00566 env->server = NULL;
00567 }
00568
00569 if (env->url)
00570 smlSafeCFree(&(env->url));
00571
00572 guint count = 0;
00573 guint removed = 0;
00574
00575
00576
00577 count = g_hash_table_size(env->uriToLink);
00578 removed = g_hash_table_foreach_steal(
00579 env->uriToLink,
00580 smlTransportHttpServerFreeUriToLink,
00581 env);
00582 if (count != removed)
00583 {
00584 smlErrorSet(error, SML_ERROR_GENERIC,
00585 "The glib function g_hash_table_foreach_steal could " \
00586 "not remove all key/value pairs from uriToLink (%u of %u).",
00587 removed, count);
00588 goto error;
00589 } else {
00590 g_hash_table_unref(env->uriToLink);
00591 env->uriToLink = NULL;
00592 }
00593
00594
00595
00596 count = g_hash_table_size(env->sessionToUri);
00597 removed = g_hash_table_foreach_steal(
00598 env->sessionToUri,
00599 smlTransportHttpServerFreeSessionToUri,
00600 env);
00601 if (count != removed)
00602 {
00603 smlErrorSet(error, SML_ERROR_GENERIC,
00604 "The glib function g_hash_table_foreach_steal could not " \
00605 "remove all key/value pairs from sessionToUri. (%u of %u)",
00606 removed, count);
00607 goto error;
00608 } else {
00609 g_hash_table_unref(env->sessionToUri);
00610 env->sessionToUri = NULL;
00611 }
00612
00613 smlSafeFree((gpointer *)&env);
00614
00615 smlTrace(TRACE_EXIT, "%s", __func__);
00616 return TRUE;
00617 error:
00618 smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
00619 return FALSE;
00620 }
00621
00622 static void smlTransportHttpServerSend(void *userdata, void *linkdata, SmlTransportData *data, SmlError *error)
00623 {
00624 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p, %p)", __func__, userdata, linkdata, data, error);
00625
00626 smlAssert(linkdata);
00627 smlAssert(error || data);
00628
00629 SmlLinkHttpServerEnv *linkenv = linkdata;
00630 smlAssert(linkenv->msg);
00631
00632 SoupMessage *msg = linkenv->msg;
00633 linkenv->msg = NULL;
00634
00635 if (error)
00636 goto error_free_message;
00637
00638 soup_message_set_status (msg, SOUP_STATUS_OK);
00639 #ifdef HAVE_LIBSOUP22
00640 soup_server_message_set_encoding (SOUP_SERVER_MESSAGE(msg), SOUP_TRANSFER_CONTENT_LENGTH);
00641 #endif
00642
00643 const char *content_type;
00644 switch (data->type) {
00645 case SML_MIMETYPE_XML:
00646 content_type = SML_ELEMENT_XML;
00647 break;
00648 case SML_MIMETYPE_WBXML:
00649 content_type = SML_ELEMENT_WBXML;
00650 break;
00651 case SML_MIMETYPE_SAN:
00652 content_type = SML_ELEMENT_SAN;
00653 break;
00654 default:
00655 smlErrorSet(&error, SML_ERROR_GENERIC, "Unknown Mimetype");
00656 goto error_free_message;
00657 }
00658
00659 #ifdef HAVE_LIBSOUP22
00660
00661 char *soupcopy = (char *) smlTryMalloc0(data->size, &error);
00662 if (error)
00663 goto error_free_message;
00664 memcpy(soupcopy, data->data, data->size);
00665 soup_message_set_response (msg, content_type, SOUP_BUFFER_SYSTEM_OWNED,
00666 soupcopy, data->size);
00667 soup_message_io_unpause(msg);
00668 #else
00669 soup_message_set_response(msg, content_type,
00670 SOUP_MEMORY_COPY, data->data, data->size);
00671 soup_server_unpause_message(linkenv->env->server, msg);
00672 #endif
00673
00674 smlTrace(TRACE_EXIT, "%s", __func__);
00675 return;
00676
00677 error_free_message:
00678 if (smlErrorGetClass(&error) <= SML_ERRORCLASS_RETRY)
00679 soup_message_set_status_full(msg, SOUP_STATUS_BAD_REQUEST, smlErrorPrint(&error));
00680 else
00681 soup_message_set_status_full(msg, SOUP_STATUS_INTERNAL_SERVER_ERROR, smlErrorPrint(&error));
00682
00683 #ifdef HAVE_LIBSOUP22
00684 soup_server_message_set_encoding (SOUP_SERVER_MESSAGE (msg), SOUP_TRANSFER_CONTENT_LENGTH);
00685 soup_message_io_unpause(msg);
00686 #else
00687 soup_server_unpause_message(linkenv->env->server, msg);
00688 #endif
00689
00690 smlErrorDeref(&error);
00691 smlTrace(TRACE_EXIT, "%s: Sent Error", __func__);
00692 return;
00693 }
00694
00695 char * smlTransportHttpServerGetResponseURI(SmlLink *link_, SmlSession *session, SmlError **error)
00696 {
00697 smlTrace(TRACE_ENTRY, "%s(%p, %p, %p)", __func__, link_, session, error);
00698
00699
00700
00701
00702 CHECK_ERROR_REF
00703 smlAssert(link_);
00704 smlAssert(session);
00705 smlAssert(link_->link_data);
00706 SmlLinkHttpServerEnv *linkenv = link_->link_data;
00707 smlAssert(linkenv->env);
00708 SmlTransportHttpServerEnv *env = linkenv->env;
00709 char *responseURI = NULL;
00710 smlTrace(TRACE_INTERNAL, "%s: params checked", __func__);
00711
00712
00713
00714
00715
00716
00717
00718
00719
00720 if (!g_hash_table_lookup(env->sessionToUri, session))
00721 {
00722
00723
00724
00725
00726 smlTrace(TRACE_INTERNAL, "%s: new session detected", __func__);
00727
00728 char *soupURI = soup_uri_to_string (soup_message_get_uri(linkenv->msg), TRUE);
00729 if (strcmp(env->url, soupURI))
00730 {
00731
00732 smlErrorSet(error, SML_ERROR_RETRY_LATER,
00733 "A new session with a configured HTTP session was detected.");
00734 smlSafeCFree(&soupURI);
00735 goto error;
00736 }
00737 smlSafeCFree(&soupURI);
00738
00739
00740
00741
00742
00743
00744
00745
00746
00747
00748
00749
00750
00751 soupURI = soup_uri_to_string (soup_message_get_uri(linkenv->msg), FALSE),
00752 responseURI = g_strdup_printf("%s0X%08X%08X%08X%08X",
00753 soupURI,
00754 g_random_int (),
00755 g_random_int (),
00756 g_random_int (),
00757 g_random_int ());
00758 smlSafeCFree(&soupURI);
00759
00760
00761 if (g_hash_table_lookup(env->uriToLink, responseURI))
00762 {
00763
00764 smlErrorSet(error, SML_ERROR_RETRY_LATER,
00765 "A fresh random session ID is already in use.");
00766 goto error;
00767 }
00768 smlLinkRef(link_);
00769 g_hash_table_insert(env->uriToLink, g_strdup(responseURI), link_);
00770 smlTrace(TRACE_INTERNAL, "%s: ResponseURI is %s.", __func__, VA_STRING(responseURI));
00771
00772
00773 g_hash_table_insert(env->sessionToUri, session, g_strdup(responseURI));
00774 smlSessionRef(session);
00775
00776
00777 linkenv->session = session;
00778 smlSessionRef(session);
00779 linkenv->url = g_strdup(responseURI);
00780 } else {
00781
00782
00783
00784
00785
00786 smlTrace(TRACE_INTERNAL, "%s: cached session detected", __func__);
00787
00788 char *soupURI = soup_uri_to_string (soup_message_get_uri(linkenv->msg), FALSE);
00789 const char *sessionURI = g_hash_table_lookup(env->sessionToUri, session);
00790 if (strcmp(soupURI, sessionURI))
00791 {
00792
00793 smlErrorSet(error, SML_ERROR_RETRY_LATER,
00794 "Another session (%s) re-used an already existing HTTP session (%s).",
00795 soupURI, sessionURI);
00796 smlSafeCFree(&soupURI);
00797 goto error;
00798 }
00799
00800 SmlLink *cachedLink = g_hash_table_lookup(env->uriToLink, soupURI);
00801 if (!cachedLink)
00802 {
00803
00804 smlErrorSet(error, SML_ERROR_GENERIC,
00805 "Cannot find link for used URL.");
00806 smlSafeCFree(&soupURI);
00807 goto error;
00808 }
00809 if (cachedLink != link_)
00810 {
00811
00812 smlErrorSet(error, SML_ERROR_GENERIC,
00813 "The link objects mismatch.");
00814 smlSafeCFree(&soupURI);
00815 goto error;
00816 }
00817 if (strcmp(linkenv->url, soupURI))
00818 {
00819
00820 smlErrorSet(error, SML_ERROR_GENERIC,
00821 "The URL of the link object is wrong.");
00822 smlSafeCFree(&soupURI);
00823 goto error;
00824 }
00825
00826 responseURI = soupURI;
00827 }
00828 smlTrace(TRACE_EXIT, "%s - %s", __func__, VA_STRING(responseURI));
00829 return responseURI;
00830 error:
00831 smlTrace(TRACE_EXIT_ERROR, "%s - %s", __func__, smlErrorPrint(error));
00832 return NULL;
00833 }
00834
00835 SmlBool smlTransportHttpServerNew(SmlTransport *tsp, SmlError **error)
00836 {
00837 smlTrace(TRACE_ENTRY, "%s(%p, %p)", __func__, tsp, error);
00838 CHECK_ERROR_REF
00839 smlAssert(tsp);
00840
00841 tsp->functions.set_config_option = smlTransportHttpServerSetConfigOption;
00842 tsp->functions.initialize = smlTransportHttpServerInit;
00843 tsp->functions.finalize = smlTransportHttpServerFinalize;
00844 tsp->functions.send = smlTransportHttpServerSend;
00845 tsp->functions.get_response_uri = smlTransportHttpServerGetResponseURI;
00846 tsp->functions.disconnect = smlTransportHttpServerDisconnect;
00847
00848 SmlTransportHttpServerEnv *env = smlTryMalloc0(sizeof(SmlTransportHttpServerEnv), error);
00849 if (!env)
00850 return FALSE;
00851 tsp->transport_data = env;
00852 env->tsp = tsp;
00853 env->sessionToUri = g_hash_table_new(g_direct_hash, g_direct_equal);
00854 env->uriToLink = g_hash_table_new_full(g_str_hash, g_str_equal, smlTransportHttpServerFreeResponseURI, NULL);
00855
00856 smlTrace(TRACE_EXIT, "%s", __func__);
00857 return TRUE;
00858 }
00859