23 #include <libsyncml/syncml.h>
24 #include <libsyncml/syncml_internals.h>
26 #include <libsyncml/sml_error_internals.h>
27 #include <libsyncml/sml_transport_internals.h>
29 #include "http_server_internals.h"
32 static void smlTransportHttpServerCallback(
33 SoupServerContext *context,
37 smlTrace(TRACE_ENTRY,
"%s(%p, %p, %p)", __func__, context, msg, data);
38 SmlMimeType mimetype = SML_MIMETYPE_UNKNOWN;
45 char *path = soup_uri_to_string (soup_message_get_uri(msg), TRUE);
46 smlTrace(TRACE_INTERNAL,
"%s: %s %s HTTP/1.%d",
47 __func__, VA_STRING(msg->method), VA_STRING(path), soup_message_get_http_version(msg));
49 if (g_strcasecmp(path, env->url)) {
52 path = soup_uri_to_string (soup_message_get_uri(msg), FALSE);
53 link_ = g_hash_table_lookup(env->uriToLink, path);
62 smlErrorSet(&error, SML_ERROR_INTERNAL_FILE_NOT_FOUND,
63 "Not Found (%s).", path);
64 soup_message_set_status(msg, SOUP_STATUS_NOT_FOUND);
72 if (soup_message_get_http_version(msg) != 1) {
73 smlErrorSet(&error, SML_ERROR_NOT_IMPLEMENTED,
"Wrong http version");
74 soup_message_set_status(msg, SOUP_STATUS_NOT_IMPLEMENTED);
78 if (soup_method_get_id(msg->method) != SOUP_METHOD_ID_POST) {
79 smlErrorSet(&error, SML_ERROR_NOT_IMPLEMENTED,
"Wrong method");
80 soup_message_set_status(msg, SOUP_STATUS_NOT_IMPLEMENTED);
84 const char *header = soup_message_get_header(msg->request_headers,
"Content-Type");
85 if (header && !g_strncasecmp(header, SML_ELEMENT_XML, strlen(SML_ELEMENT_XML)))
86 mimetype = SML_MIMETYPE_XML;
87 else if(header && !g_strncasecmp(header, SML_ELEMENT_WBXML, strlen(SML_ELEMENT_WBXML)))
88 mimetype = SML_MIMETYPE_WBXML;
89 else if(header && !g_strncasecmp(header, SML_ELEMENT_SAN, strlen(SML_ELEMENT_SAN)))
90 mimetype = SML_MIMETYPE_SAN;
92 smlErrorSet(&error, SML_ERROR_GENERIC,
"Unknown mimetype");
93 soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST);
96 smlErrorSet(&error, SML_ERROR_GENERIC,
"Faulty mimetype");
97 soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST);
113 link_ = smlLinkNew(env->tsp, linkenv, &error);
118 linkenv->link = link_;
119 smlLinkRef(linkenv->link);
123 smlTransportReceiveEvent(env->tsp, link_, SML_TRANSPORT_EVENT_CONNECT_DONE, NULL, NULL);
126 linkenv = link_->link_data;
129 "%s: WARNING: ResponseURI should not be in use - test mode.",
134 smlTrace(TRACE_INTERNAL,
"%s: The message length is %i.", __func__, msg->request.length);
147 memcpy(body, msg->request.body, msg->request.length);
149 SmlTransportData *tspdata = smlTransportDataNew(body, msg->request.length, mimetype, TRUE, &error);
152 goto error_unref_msg;
154 smlTransportReceiveEvent(env->tsp, link_, SML_TRANSPORT_EVENT_DATA, tspdata, NULL);
157 smlTransportDataDeref(tspdata);
159 soup_message_io_pause(msg);
161 smlTrace(TRACE_EXIT,
"%s", __func__);
165 link_->link_data = NULL;
168 smlSafeFree((gpointer *) &linkenv);
170 soup_server_message_set_encoding (SOUP_SERVER_MESSAGE (msg), SOUP_TRANSFER_CONTENT_LENGTH);
171 soup_message_io_unpause(msg);
173 smlErrorDeref(&error);
178 static void smlTransportHttpServerCallback(
183 SoupClientContext *client,
186 smlTrace(TRACE_ENTRY,
"%s(%p, %p, %s, %p, %p, %p)", __func__, server, msg, VA_STRING(path), query, client, data);
187 SmlMimeType mimetype = SML_MIMETYPE_UNKNOWN;
194 smlTrace(TRACE_INTERNAL,
"%s: %s %s HTTP/1.%d",
195 __func__, VA_STRING(msg->method), VA_STRING(path), soup_message_get_http_version(msg));
197 if (msg->method != SOUP_METHOD_POST) {
198 smlErrorSet(&error, SML_ERROR_NOT_IMPLEMENTED,
"Wrong method");
199 soup_message_set_status(msg, SOUP_STATUS_NOT_IMPLEMENTED);
203 if (g_strcasecmp(path, env->url)) {
205 char *fullpath = soup_uri_to_string (soup_message_get_uri(msg), FALSE);
206 link_ = g_hash_table_lookup(env->uriToLink, fullpath);
215 smlErrorSet(&error, SML_ERROR_INTERNAL_FILE_NOT_FOUND,
216 "Not Found (%s).", fullpath);
217 soup_message_set_status(msg, SOUP_STATUS_NOT_FOUND);
218 smlSafeCFree(&fullpath);
222 smlSafeCFree(&fullpath);
225 const char *header = soup_message_headers_get(msg->request_headers,
"Content-Type");
226 if (header && !g_strncasecmp(header, SML_ELEMENT_XML, strlen(SML_ELEMENT_XML)))
227 mimetype = SML_MIMETYPE_XML;
228 else if(header && !g_strncasecmp(header, SML_ELEMENT_WBXML, strlen(SML_ELEMENT_WBXML)))
229 mimetype = SML_MIMETYPE_WBXML;
230 else if(header && !g_strncasecmp(header, SML_ELEMENT_SAN, strlen(SML_ELEMENT_SAN)))
231 mimetype = SML_MIMETYPE_SAN;
233 smlErrorSet(&error, SML_ERROR_GENERIC,
"Unknown mimetype");
234 soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST);
237 smlErrorSet(&error, SML_ERROR_GENERIC,
"Faulty mimetype");
238 soup_message_set_status (msg, SOUP_STATUS_BAD_REQUEST);
254 link_ = smlLinkNew(env->tsp, linkenv, &error);
259 linkenv->link = link_;
260 smlLinkRef(linkenv->link);
264 smlTransportReceiveEvent(env->tsp, link_, SML_TRANSPORT_EVENT_CONNECT_DONE, NULL, NULL);
266 linkenv = link_->link_data;
269 "%s: WARNING: ResponseURI should not be in use - test mode.",
274 if (msg->request_body) {
275 smlTrace(TRACE_INTERNAL,
"%s: The message length is %i.",
276 __func__, msg->request_body->length);
278 smlTrace(TRACE_INTERNAL,
"%s: The message has no request body.", __func__);
289 char *body =
smlTryMalloc0(msg->request_body->length + 1, &error);
292 memcpy(body, msg->request_body->data, msg->request_body->length);
294 SmlTransportData *tspdata = smlTransportDataNew(body, msg->request_body->length, mimetype, TRUE, &error);
297 goto error_unref_msg;
299 smlTransportReceiveEvent(env->tsp, link_, SML_TRANSPORT_EVENT_DATA, tspdata, NULL);
304 smlTransportDataDeref(tspdata);
306 soup_server_pause_message(server, msg);
308 smlTrace(TRACE_EXIT,
"%s", __func__);
315 smlErrorDeref(&error);
320 static SmlBool smlTransportHttpServerSetConfigOption(
326 smlTrace(TRACE_ENTRY,
"%s(%p, %s, %s, %p)", __func__, tsp, VA_STRING(name), VA_STRING(value), error);
329 smlAssert(tsp->transport_data);
332 if (!strcmp(name, SML_TRANSPORT_CONFIG_PORT)) {
333 env->port = atoi(value);
334 if (!(env->port > 0 && env->port < 65535)) {
335 smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION,
"specified port was wrong");
339 smlTrace(TRACE_INTERNAL,
"%s: Port %i detected", __func__, env->port);
340 }
else if (!strcmp(name, SML_TRANSPORT_CONFIG_URL)) {
341 env->url = g_strdup(value);
342 smlTrace(TRACE_INTERNAL,
"%s: URL %s detected", __func__, VA_STRING(env->url));
343 }
else if (!strcmp(name, SML_TRANSPORT_CONFIG_SSL_KEY)) {
344 env->ssl_key = g_strdup(value);
345 smlTrace(TRACE_INTERNAL,
"%s: SSL key %s detected", __func__, VA_STRING(env->ssl_key));
346 }
else if (!strcmp(name, SML_TRANSPORT_CONFIG_SSL_SERVER_CERT)) {
347 env->ssl_cert = g_strdup(value);
348 smlTrace(TRACE_INTERNAL,
"%s: SSL server certificate %s detected", __func__, VA_STRING(env->ssl_cert));
350 smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION,
"Unknown parameter %s found.", name);
355 smlTrace(TRACE_EXIT,
"%s", __func__);
361 smlTrace(TRACE_ENTRY,
"%s(%p, %p)", __func__, tsp, error);
364 smlAssert(tsp->context);
365 smlAssert(tsp->transport_data);
370 smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION,
371 "The HTTP server needs a port where it has to run.");
378 env->url = g_strdup(
"/");
381 smlTrace(TRACE_INTERNAL,
"%s: config: port %i, url %s", __func__, env->port, VA_STRING(env->url));
382 smlTrace(TRACE_INTERNAL,
"%s: http server uses context %p.", __func__, tsp->context);
384 if(!env->ssl_key || !env->ssl_cert) {
385 env->server = soup_server_new(
386 SOUP_SERVER_ASYNC_CONTEXT, tsp->context,
387 SOUP_SERVER_PORT, env->port,
390 env->server = soup_server_new(
391 SOUP_SERVER_ASYNC_CONTEXT, tsp->context,
392 SOUP_SERVER_PORT, env->port,
393 SOUP_SERVER_SSL_CERT_FILE, env->ssl_cert,
394 SOUP_SERVER_SSL_KEY_FILE, env->ssl_key,
398 smlErrorSet(error, SML_ERROR_INTERNAL_MISCONFIGURATION,
"Unable to spawn server");
402 #ifdef HAVE_LIBSOUP22
403 soup_server_add_handler(env->server, NULL, NULL, smlTransportHttpServerCallback, NULL, env);
405 soup_server_add_handler(env->server, NULL, smlTransportHttpServerCallback, env, NULL);
408 soup_server_run_async(env->server);
410 smlTrace(TRACE_EXIT,
"%s", __func__);
415 smlSafeCFree(&(env->url));
417 smlSafeFree((gpointer *)&env);
423 static void smlTransportHttpServerDisconnect(
void *data,
void *linkdata)
425 smlTrace(TRACE_ENTRY,
"%s(%p, %p)", __func__, data, linkdata);
431 smlTrace(TRACE_INTERNAL,
"%s: remove link from session/uri cache", __func__);
432 if (linkenv->session)
434 char *uri = g_hash_table_lookup(linkenv->env->sessionToUri, linkenv->session);
435 g_hash_table_remove(linkenv->env->sessionToUri, linkenv->session);
441 smlSessionUnref(linkenv->session);
442 smlSessionUnref(linkenv->session);
443 linkenv->session = NULL;
448 smlTrace(TRACE_INTERNAL,
"%s: remove link from uri/link cache", __func__);
451 link_ = g_hash_table_lookup(linkenv->env->uriToLink, linkenv->url);
452 g_hash_table_remove(linkenv->env->uriToLink, linkenv->url);
454 smlSafeCFree(&(linkenv->url));
458 link_ = linkenv->link;
463 smlTrace(TRACE_INTERNAL,
"%s: close open message/connection", __func__);
464 soup_message_set_status (linkenv->msg, SOUP_STATUS_SERVICE_UNAVAILABLE);
465 #ifdef HAVE_LIBSOUP22
469 soup_message_io_unpause(linkenv->msg);
471 soup_server_unpause_message(linkenv->env->server, linkenv->msg);
477 smlTrace(TRACE_INTERNAL,
"%s: free memory", __func__);
479 link_->link_data = NULL;
480 smlSafeFree((gpointer *)&linkenv);
482 smlTrace(TRACE_INTERNAL,
"%s: signal and unref link", __func__);
483 smlTransportReceiveEvent(env->tsp, link_, SML_TRANSPORT_EVENT_DISCONNECT_DONE, NULL, NULL);
485 smlTrace(TRACE_EXIT,
"%s", __func__);
488 static void smlTransportHttpServerFreeResponseURI(gpointer key)
490 smlTrace(TRACE_ENTRY,
"%s(%p)", __func__, key);
491 smlSafeCFree((
char **)&key);
492 smlTrace(TRACE_EXIT,
"%s", __func__);
495 static gboolean smlTransportHttpServerFreeUriToLink(
500 smlTrace(TRACE_ENTRY,
"%s(%p, %p, %p)", __func__, key, value, user_data);
508 smlTrace(TRACE_EXIT,
"%s", __func__);
512 static gboolean smlTransportHttpServerFreeSessionToUri(
517 smlTrace(TRACE_ENTRY,
"%s(%p, %p, %p)", __func__, key, value, user_data);
523 smlSessionUnref(session);
525 smlTrace(TRACE_EXIT,
"%s", __func__);
529 static SmlBool smlTransportHttpServerCleanupSocket(
533 smlTrace(TRACE_ENTRY,
"%s", __func__);
537 SoupServer *server = data;
539 soup_server_quit(server);
540 g_object_unref(server);
542 smlTrace(TRACE_EXIT,
"%s", __func__);
546 static SmlBool smlTransportHttpServerFinalize(
void *data,
SmlError **error)
548 smlTrace(TRACE_ENTRY,
"%s(%p, %p)", __func__, data, error);
562 smlTransportHttpServerCleanupSocket,
570 smlSafeCFree(&(env->url));
577 count = g_hash_table_size(env->uriToLink);
578 removed = g_hash_table_foreach_steal(
580 smlTransportHttpServerFreeUriToLink,
582 if (count != removed)
585 "The glib function g_hash_table_foreach_steal could " \
586 "not remove all key/value pairs from uriToLink (%u of %u).",
590 g_hash_table_unref(env->uriToLink);
591 env->uriToLink = NULL;
596 count = g_hash_table_size(env->sessionToUri);
597 removed = g_hash_table_foreach_steal(
599 smlTransportHttpServerFreeSessionToUri,
601 if (count != removed)
604 "The glib function g_hash_table_foreach_steal could not " \
605 "remove all key/value pairs from sessionToUri. (%u of %u)",
609 g_hash_table_unref(env->sessionToUri);
610 env->sessionToUri = NULL;
613 smlSafeFree((gpointer *)&env);
615 smlTrace(TRACE_EXIT,
"%s", __func__);
624 smlTrace(TRACE_ENTRY,
"%s(%p, %p, %p, %p)", __func__, userdata, linkdata, data, error);
627 smlAssert(error || data);
630 smlAssert(linkenv->msg);
632 SoupMessage *msg = linkenv->msg;
636 goto error_free_message;
638 soup_message_set_status (msg, SOUP_STATUS_OK);
639 #ifdef HAVE_LIBSOUP22
640 soup_server_message_set_encoding (SOUP_SERVER_MESSAGE(msg), SOUP_TRANSFER_CONTENT_LENGTH);
643 const char *content_type;
644 switch (data->type) {
645 case SML_MIMETYPE_XML:
646 content_type = SML_ELEMENT_XML;
648 case SML_MIMETYPE_WBXML:
649 content_type = SML_ELEMENT_WBXML;
651 case SML_MIMETYPE_SAN:
652 content_type = SML_ELEMENT_SAN;
655 smlErrorSet(&error, SML_ERROR_GENERIC,
"Unknown Mimetype");
656 goto error_free_message;
659 #ifdef HAVE_LIBSOUP22
663 goto error_free_message;
664 memcpy(soupcopy, data->data, data->size);
665 soup_message_set_response (msg, content_type, SOUP_BUFFER_SYSTEM_OWNED,
666 soupcopy, data->size);
667 soup_message_io_unpause(msg);
669 soup_message_set_response(msg, content_type,
670 SOUP_MEMORY_COPY, data->data, data->size);
671 soup_server_unpause_message(linkenv->env->server, msg);
674 smlTrace(TRACE_EXIT,
"%s", __func__);
679 soup_message_set_status_full(msg, SOUP_STATUS_BAD_REQUEST,
smlErrorPrint(&error));
681 soup_message_set_status_full(msg, SOUP_STATUS_INTERNAL_SERVER_ERROR,
smlErrorPrint(&error));
683 #ifdef HAVE_LIBSOUP22
684 soup_server_message_set_encoding (SOUP_SERVER_MESSAGE (msg), SOUP_TRANSFER_CONTENT_LENGTH);
685 soup_message_io_unpause(msg);
687 soup_server_unpause_message(linkenv->env->server, msg);
690 smlErrorDeref(&error);
691 smlTrace(TRACE_EXIT,
"%s: Sent Error", __func__);
697 smlTrace(TRACE_ENTRY,
"%s(%p, %p, %p)", __func__, link_, session, error);
705 smlAssert(link_->link_data);
707 smlAssert(linkenv->env);
709 char *responseURI = NULL;
710 smlTrace(TRACE_INTERNAL,
"%s: params checked", __func__);
720 if (!g_hash_table_lookup(env->sessionToUri, session))
726 smlTrace(TRACE_INTERNAL,
"%s: new session detected", __func__);
728 char *soupURI = soup_uri_to_string (soup_message_get_uri(linkenv->msg), TRUE);
729 if (strcmp(env->url, soupURI))
733 "A new session with a configured HTTP session was detected.");
734 smlSafeCFree(&soupURI);
737 smlSafeCFree(&soupURI);
751 soupURI = soup_uri_to_string (soup_message_get_uri(linkenv->msg), FALSE),
752 responseURI = g_strdup_printf(
"%s0X%08X%08X%08X%08X",
758 smlSafeCFree(&soupURI);
761 if (g_hash_table_lookup(env->uriToLink, responseURI))
765 "A fresh random session ID is already in use.");
769 g_hash_table_insert(env->uriToLink, g_strdup(responseURI), link_);
770 smlTrace(TRACE_INTERNAL,
"%s: ResponseURI is %s.", __func__, VA_STRING(responseURI));
773 g_hash_table_insert(env->sessionToUri, session, g_strdup(responseURI));
774 smlSessionRef(session);
777 linkenv->session = session;
778 smlSessionRef(session);
779 linkenv->url = g_strdup(responseURI);
786 smlTrace(TRACE_INTERNAL,
"%s: cached session detected", __func__);
788 char *soupURI = soup_uri_to_string (soup_message_get_uri(linkenv->msg), FALSE);
789 const char *sessionURI = g_hash_table_lookup(env->sessionToUri, session);
790 if (strcmp(soupURI, sessionURI))
794 "Another session (%s) re-used an already existing HTTP session (%s).",
795 soupURI, sessionURI);
796 smlSafeCFree(&soupURI);
800 SmlLink *cachedLink = g_hash_table_lookup(env->uriToLink, soupURI);
805 "Cannot find link for used URL.");
806 smlSafeCFree(&soupURI);
809 if (cachedLink != link_)
813 "The link objects mismatch.");
814 smlSafeCFree(&soupURI);
817 if (strcmp(linkenv->url, soupURI))
821 "The URL of the link object is wrong.");
822 smlSafeCFree(&soupURI);
826 responseURI = soupURI;
828 smlTrace(TRACE_EXIT,
"%s - %s", __func__, VA_STRING(responseURI));
837 smlTrace(TRACE_ENTRY,
"%s(%p, %p)", __func__, tsp, error);
841 tsp->functions.set_config_option = smlTransportHttpServerSetConfigOption;
842 tsp->functions.initialize = smlTransportHttpServerInit;
843 tsp->functions.finalize = smlTransportHttpServerFinalize;
844 tsp->functions.send = smlTransportHttpServerSend;
845 tsp->functions.get_response_uri = smlTransportHttpServerGetResponseURI;
846 tsp->functions.disconnect = smlTransportHttpServerDisconnect;
851 tsp->transport_data = env;
853 env->sessionToUri = g_hash_table_new(g_direct_hash, g_direct_equal);
854 env->uriToLink = g_hash_table_new_full(g_str_hash, g_str_equal, smlTransportHttpServerFreeResponseURI, NULL);
856 smlTrace(TRACE_EXIT,
"%s", __func__);
const char * smlErrorPrint(SmlError **error)
Returns the message of the error.
SmlBool smlThreadCallFunction(SmlThread *thread, SmlThreadCallFunctionType func, gpointer data, SmlError **error)
SmlErrorClass smlErrorGetClass(SmlError **error)
Gets the error class.
void smlTrace(SmlTraceType type, const char *message,...)
Used for tracing the application.
void * smlTryMalloc0(long n_bytes, SmlError **error)
Safely mallocs.
void smlErrorSet(SmlError **error, SmlErrorType type, const char *format,...)
Sets the error.