26#include <glib/gi18n.h>
33#ifndef LIBSOUP_VERSION_MAJOR
34#error "LIBSOUP_VERSION_MAJOR not defined by CMake"
36#if LIBSOUP_VERSION_MAJOR >= 3
54 "<meta http-equiv=\"Content-Type\" content=\"text/html; charset=utf-8\">\n"
58 " background-color: #575656;\n"
59 " font-family: \"Lucida Grande\",Verdana,\"Bitstream Vera Sans\",Arial,sans-serif;\n"
61 " padding: 50px 100px 50px 100px;\n"
64 " background-color: #cfcece;\n"
65 " border: 1px solid #000;\n"
66 " padding: 0px 40px 40px 40px;\n"
70 " if(window.location.hash && %d) {\n"
71 " var hash = window.location.hash.substring(1);\n"
72 " window.location.search = hash;\n"
76 "<body><div id=\"content\">\n"
77 "<div style=\"font-size: 42pt; font-weight: bold; color: white; text-align: right;\">%s</div>\n"
85static gboolean _delayed_kill(gpointer user_data)
88 return G_SOURCE_REMOVE;
100static void _new_connection(SoupServer *server, SoupMessage *msg,
const char *path, GHashTable *query,
101 SoupClientContext *client, gpointer user_data)
106 if(msg->method != SOUP_METHOD_GET)
108 soup_message_set_status(msg, SOUP_STATUS_NOT_IMPLEMENTED);
112 char *page_title = g_strdup_printf(_(
"ansel >> %s"), params->id);
113 const char *title = _(params->id);
114 const char *body = _(
"<h1>Sorry,</h1><p>something went wrong. Please try again.</p>");
116 res = params->callback(query, params->user_data);
119 body = _(
"<h1>Thank you,</h1><p>everything should have worked, you can <b>close</b> your browser now and "
120 "<b>go back</b> to Ansel.</p>");
122 char *resp_body = g_strdup_printf(
reply, page_title,
res ? 0 : 1, title, body);
123 size_t resp_length = strlen(resp_body);
126 soup_message_set_status(msg, SOUP_STATUS_OK);
127 soup_message_set_response(msg,
"text/html", SOUP_MEMORY_TAKE, resp_body, resp_length);
133 soup_server_remove_handler(server, path);
141static void _new_connection(SoupServer *server, SoupServerMessage *msg, gpointer user_data)
145 if(g_strcmp0(soup_server_message_get_method(msg), SOUP_METHOD_GET) != 0)
147 soup_server_message_set_status(msg, SOUP_STATUS_NOT_IMPLEMENTED,
"Not Implemented");
154 g_hash_table_unref(query);
156 const char *body =
res ?
157 _(
"<h1>Thank you,</h1><p>everything should have worked, you can <b>close</b> your browser now and "
158 "<b>go back</b> to Ansel.</p>") :
159 _(
"<h1>Sorry,</h1><p>something went wrong. Please try again.</p>");
161 char *page_title = g_strdup_printf(_(
"ansel >> %s"),
params->id);
162 char *resp_body = g_strdup_printf(
reply, page_title,
res ? 0 : 1, _(
params->id), body);
165 soup_server_message_set_status(msg, SOUP_STATUS_OK,
"OK");
166 soup_server_message_set_response(msg,
"text/html; charset=utf-8",
167 SOUP_MEMORY_TAKE, resp_body, strlen(resp_body));
170 g_timeout_add(100, _delayed_kill,
params->server);
177 SoupServer *httpserver = NULL;
184 httpserver = soup_server_new(SOUP_SERVER_SERVER_HEADER,
"ansel internal server", NULL);
187 fprintf(stderr,
"error: couldn't create libsoup httpserver\n");
191 for(
int i = 0;
i < n_ports;
i++)
194 if(soup_server_listen_local(httpserver, port, 0, NULL))
break;
199 g_object_unref(httpserver);
200 fprintf(stderr,
"error: can't bind to any port from our pool\n");
206#elif defined(LIBSOUP3)
208SoupServerListener *listener = soup_server_get_listener(httpserver);
210 GMainContext *ctx = g_main_context_default();
211 soup_server_listener_set_context(listener, ctx);
213soup_server_run(httpserver);
216#elif defined(LIBSOUP3)
220 httpserver = soup_server_new(
"server-header",
"ansel internal server", NULL);
223 fprintf(stderr,
"error: couldn't create libsoup httpserver\n");
227 for(
int i = 0;
i < n_ports;
i++)
230 if(soup_server_listen_local(httpserver, port, SOUP_SERVER_LISTEN_IPV4_ONLY, NULL))
break;
235 g_object_unref(httpserver);
236 fprintf(stderr,
"error: can't bind to any port from our pool\n");
242 server->
server = httpserver;
246 params->server = server;
247 params->callback = callback;
248 params->user_data = user_data;
250 char *path = g_strdup_printf(
"/%s",
id);
251 server->
url = g_strdup_printf(
"http://localhost:%d%s", port, path);
254 soup_server_add_handler(httpserver, path,
_new_connection, params, (GDestroyNotify)free);
256 soup_server_add_early_handler(httpserver, path, (SoupServerCallback)
_new_connection, params, (GDestroyNotify)g_free);
267 if(server && server->
server)
269 soup_server_disconnect(server->
server);
270 g_object_unref(server->
server);
void dt_http_server_kill(dt_http_server_t *server)
static void _request_finished_callback(SoupServer *server, SoupMessage *message, SoupClientContext *client, gpointer user_data)
static void _new_connection(SoupServer *server, SoupMessage *msg, const char *path, GHashTable *query, SoupClientContext *client, gpointer user_data)
static const char reply[]
dt_http_server_t * dt_http_server_create(const int *ports, const int n_ports, const char *id, const dt_http_server_callback callback, gpointer user_data)
gboolean(* dt_http_server_callback)(GHashTable *query, gpointer user_data)
void dt_print(dt_debug_thread_t thread, const char *msg,...) __attribute__((format(printf
Print to stdout when thread is enabled, prefixed with seconds since startup.
#define IS_NULL_PTR(p)
C is way too permissive with !=, == and if(var) checks, which can mean too many things depending on w...
static void dt_free_gpointer(gpointer ptr)
g_free() one pointer, with the signature GDestroyNotify wants.
#define dt_free(ptr)
g_free() ptr and set it to NULL, skipping both if it is already NULL.
dt_http_server_callback callback
dt_http_server_t * server