summaryrefslogtreecommitdiffstats
path: root/src/httpd.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/httpd.c')
-rw-r--r--src/httpd.c169
1 files changed, 169 insertions, 0 deletions
diff --git a/src/httpd.c b/src/httpd.c
new file mode 100644
index 0000000..bf5c3d1
--- /dev/null
+++ b/src/httpd.c
@@ -0,0 +1,169 @@
+char * sc_queryhtml (struct sc_query * q) { /* remember to free returned string in the caller */ /* caller takes care of locking */
+ size_t resultshtml_written = 0;
+ size_t resultshtml_sizeof = SC_ALLOC_CHUNK;
+ char * resultshtml = malloc(resultshtml_sizeof);
+ resultshtml[0] = '\0';
+ for (size_t i = 0; i < q->results_length; i++) {
+#define SC_HRC(string, wanted) \
+ if (string##_written+wanted >= string##_sizeof) { \
+ string##_sizeof = (string##_written+wanted+1)*SC_REALLOC_K; \
+ string = realloc(string, string##_sizeof); \
+ }
+#define SC_HRF "<div class=result><h4><a href=\"%s\">%s</a></h4><p>%s</p></div>"
+ char * safetitle = htmlspecialchars(q->results[i]->title);
+ char * safebody = htmlspecialchars(q->results[i]->desc);
+ char * safeurl = htmlspecialchars(q->results[i]->url);
+ size_t ws = snprintf(NULL, 0, SC_HRF, safeurl, safetitle, safebody);
+ SC_HRC(resultshtml, ws);
+ resultshtml_written += sprintf(resultshtml+resultshtml_written, SC_HRF, safeurl, safetitle, safebody);
+ free(safetitle);
+ free(safebody);
+ free(safeurl);
+ }
+#define SC_HRS SC_I18N_NUMBER_OF_RESULTS ": %ld | " SC_I18N_QUERY_TIME ": %s"
+ char formatted_time[128];
+ struct tm tm;
+ localtime_r(&q->lookup_time, &tm);
+ strftime(formatted_time, 128, SC_I18N_DATETIME_FORMAT, &tm);
+ char queryinfo[256];
+ snprintf(queryinfo, 256, SC_HRS, q->results_length, formatted_time);
+ char * safequery = htmlspecialchars(q->string);
+ char * response = malloc(strlen((char *) sc_hp)+2*strlen(safequery)+strlen(queryinfo)+strlen(resultshtml));
+ sprintf(response, (char *) sc_hp, safequery, safequery, queryinfo, resultshtml);
+ free(safequery);
+ free(resultshtml);
+ return response;
+}
+char * sc_logshtml (struct sc_cache * c) { /* remember to free on caller, remember not to report errors here whilst locked */
+ char * html = malloc(SC_ALLOC_CHUNK);
+ html[0] = '\0';
+ size_t html_written = 0;
+ size_t html_sizeof = 0;
+ pthread_rwlock_rdlock(c->logentries_lock);
+ if (!c->logentries) {
+ free(html);
+ return NULL;
+ }
+ for (size_t i = 0; i < c->logentries_length; i++) {
+#define SC_HLF "<div class=result id=log%lu>[<span class=%s>%s</span>] %s " \
+ "<a href=\"" SC_I18N_GIT_URL "/src/branch/master/%s#L%lu\">%s()@%s:%lu</a>: %s</div>"
+#define SC_HLA i, \
+ sc_log_str(c->logentries[i]->type), \
+ sc_log_str(c->logentries[i]->type), \
+ formatted_time, \
+ c->logentries[i]->file, \
+ c->logentries[i]->line, \
+ c->logentries[i]->function, /* compile-time burned in values are safe from xss :) */ \
+ c->logentries[i]->file, \
+ c->logentries[i]->line, \
+ safemessage /* ... whereas this might contain < */
+ struct tm tm;
+ char formatted_time[128];
+ localtime_r(&c->logentries[i]->time, &tm);
+ strftime(formatted_time, 128, SC_I18N_DATETIME_FORMAT, &tm);
+ char * safemessage = htmlspecialchars(c->logentries[i]->message);
+ size_t ws = snprintf(NULL, 0, SC_HLF, SC_HLA);
+ SC_HRC(html, ws);
+ html_written += sprintf(html+html_written, SC_HLF, SC_HLA);
+ free(safemessage);
+ }
+ pthread_rwlock_unlock(c->logentries_lock);
+ return html;
+}
+int sc_httpd (void * cls,
+ struct MHD_Connection * connection,
+ const char * url,
+ const char * method,
+ const char * version,
+ const char * upload_data,
+ size_t * upload_data_size,
+ void ** ptr) {
+ struct sc_cache * c = (struct sc_cache *) cls;
+ static int dummy;
+ struct MHD_Response * httpd_response;
+ int ret;
+ if (0 != strcmp(method, "GET"))
+ return MHD_NO; /* unexpected method */
+ if (&dummy != *ptr) {
+ /* the first time only the headers are valid, do not respond in the first round ... */
+ *ptr = &dummy;
+ return MHD_YES;
+ }
+ if (0 != *upload_data_size)
+ return MHD_NO; /* upload data in a GET?! */
+ *ptr = NULL; /* clear context pointer */
+ char * response = NULL;
+ enum MHD_ResponseMemoryMode mhdrmm = MHD_RESPMEM_MUST_FREE;
+ const char * query = MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "q");
+ const char * host = MHD_lookup_connection_value(connection, MHD_HEADER_KIND, "Host");
+ char * location = "//git.sijanec.eu/sijanec/sear.c";
+ char * content_type = "text/html";
+ int status_code = MHD_HTTP_OK;
+ if (!host)
+ host = "";
+ struct sc_query * q = NULL;
+ if (!query) {
+ if (url[0] == '/')
+ switch (url[1]) {
+ case 's': /* security.txt */
+ case '.': /* .well-known/security.txt */
+ mhdrmm = MHD_RESPMEM_PERSISTENT;
+ response = sc_securitytxt;
+ content_type = "text/plain";
+ break;
+ case 'r': /* robots.txt */
+ mhdrmm = MHD_RESPMEM_PERSISTENT;
+ response = sc_robotstxt;
+ content_type = "text/plain";
+ break;
+ case 'o': /* osdd.xml - opensearch description document */
+ response = malloc(strlen(sc_osdd)+strlen(host));
+ sprintf(response, sc_osdd, host);
+ content_type = "application/opensearchdescription+xml";
+ break;
+ case 'l': /* logs.html */
+ {
+ char * logshtml = sc_logshtml(c);
+ response = malloc(strlen((char *) sc_hp)+strlen(SC_I18N_LOGS)+strlen(logshtml ? logshtml : SC_I18N_LOGS_ERROR));
+ sprintf(response, (char *) sc_hp, "", "", SC_I18N_LOGS, logshtml ? logshtml : SC_I18N_LOGS_ERROR);
+ free(logshtml);
+ }
+ break;
+ }
+ if (!response) {
+ response = malloc(strlen((char *) sc_hp)+strlen(SC_I18N_HP_HEADING)+strlen(SC_I18N_HP_BODY));
+ sprintf(response, (char *) sc_hp, "", "", SC_I18N_HP_HEADING, SC_I18N_HP_BODY);
+ }
+ } else {
+ int already_retried = 0;
+retry:
+ SC_CRLE(c, c->queries_lock);
+ for (size_t i = 0; i < c->queries_length; i++)
+ if (!strcmp(c->queries[i]->string, query))
+ q = c->queries[i];
+ if (q) {
+ response = sc_queryhtml(q); /* MHD_create_response_from_buffer will free response (; */
+ if (MHD_lookup_connection_value(connection, MHD_GET_ARGUMENT_KIND, "f") && q->results_length > 0) {
+ status_code = 307;
+ location = q->results[0]->url;
+ }
+ SC_CUE(c, c->queries_lock);
+ } else {
+ SC_CUE(c, c->queries_lock);
+ sc_query_google(query, c, NULL);
+ if (already_retried++) {
+ char * safequery = htmlspecialchars(query);
+ response = malloc(strlen((char*) sc_hp)+strlen(safequery)*2+strlen(SC_I18N_HP_ERROR_HEADING)+strlen(SC_I18N_HP_ERROR_BODY));
+ sprintf(response, (char *) sc_hp, safequery, safequery, SC_I18N_HP_ERROR_HEADING, SC_I18N_HP_ERROR_BODY);
+ free(safequery);
+ } else goto retry;
+ }
+ }
+ httpd_response = MHD_create_response_from_buffer (strlen(response), (void *) response, mhdrmm);
+ MHD_add_response_header(httpd_response, "Content-Type", content_type);
+ if (status_code >= 300 && status_code <= 399)
+ MHD_add_response_header(httpd_response, "Location", location);
+ ret = MHD_queue_response(connection, status_code, httpd_response);
+ MHD_destroy_response(httpd_response);
+ return ret;
+}