123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333 |
- #include "xs.h"
- #include "xs_io.h"
- #include "xs_encdec.h"
- #include "xs_json.h"
- #include "xs_socket.h"
- #include "xs_httpd.h"
- #include "xs_mime.h"
- #include "snac.h"
- #include <setjmp.h>
- #include <pthread.h>
- const char *susie =
- "iVBORw0KGgoAAAANSUhEUgAAAEAAAABAAQAAAAC"
- "CEkxzAAAAUUlEQVQoz43R0QkAMQwCUDdw/y3dwE"
- "vsvzlL4X1IoQkAisKmwfAFT3RgJHbQezpSRoXEq"
- "eqCL9BJBf7h3QbOCCxV5EVWMEMwG7K1/WODtlvx"
- "AYTtEsDU9F34AAAAAElFTkSuQmCC";
- int server_get_handler(d_char *req, char *q_path,
- char **body, int *b_size, char **ctype)
- {
- int status = 0;
- char *acpt = xs_dict_get(req, "accept");
- if (acpt == NULL)
- return 0;
-
- if (*q_path == '\0') {
-
- xs *fn = xs_fmt("%s/greeting.html", srv_basedir);
- FILE *f;
- if ((f = fopen(fn, "r")) != NULL) {
- d_char *s = xs_readall(f);
- fclose(f);
- status = 200;
-
- s = xs_replace_i(s, "%host%", xs_dict_get(srv_config, "host"));
-
- if (xs_str_in(s, "%userlist%") != -1) {
- char *host = xs_dict_get(srv_config, "host");
- xs *list = user_list();
- char *p, *uid;
- xs *ul = xs_str_new("<ul class=\"snac-user-list\">\n");
- p = list;
- while (xs_list_iter(&p, &uid)) {
- snac snac;
- if (user_open(&snac, uid)) {
- xs *u = xs_fmt(
- "<li><a href=\"%s\">@%s@%s (%s)</a></li>\n",
- snac.actor, uid, host,
- xs_dict_get(snac.config, "name"));
- ul = xs_str_cat(ul, u);
- user_free(&snac);
- }
- }
- ul = xs_str_cat(ul, "</ul>\n");
- s = xs_replace_i(s, "%userlist%", ul);
- }
- *body = s;
- }
- }
- else
- if (strcmp(q_path, "/susie.png") == 0) {
- status = 200;
- *body = xs_base64_dec(susie, b_size);
- *ctype = "image/png";
- }
- if (status != 0)
- srv_debug(1, xs_fmt("server_get_handler serving '%s' %d", q_path, status));
- return status;
- }
- void httpd_connection(FILE *f)
- {
- xs *req;
- char *method;
- int status = 0;
- char *body = NULL;
- int b_size = 0;
- char *ctype = NULL;
- xs *headers = NULL;
- xs *q_path = NULL;
- xs *payload = NULL;
- int p_size = 0;
- char *p;
- req = xs_httpd_request(f, &payload, &p_size);
- if (req == NULL) {
-
- fclose(f);
- return;
- }
- method = xs_dict_get(req, "method");
- q_path = xs_dup(xs_dict_get(req, "path"));
-
- if (xs_endswith(q_path, "/"))
- q_path = xs_crop(q_path, 0, -1);
- p = xs_dict_get(srv_config, "prefix");
- if (xs_startswith(q_path, p))
- q_path = xs_crop(q_path, strlen(p), 0);
- if (strcmp(method, "GET") == 0 || strcmp(method, "HEAD") == 0) {
-
- if (status == 0)
- status = server_get_handler(req, q_path, &body, &b_size, &ctype);
- if (status == 0)
- status = webfinger_get_handler(req, q_path, &body, &b_size, &ctype);
- if (status == 0)
- status = activitypub_get_handler(req, q_path, &body, &b_size, &ctype);
- if (status == 0)
- status = html_get_handler(req, q_path, &body, &b_size, &ctype);
- }
- else
- if (strcmp(method, "POST") == 0) {
- if (status == 0)
- status = activitypub_post_handler(req, q_path,
- payload, p_size, &body, &b_size, &ctype);
- if (status == 0)
- status = html_post_handler(req, q_path,
- payload, p_size, &body, &b_size, &ctype);
- }
-
- headers = xs_dict_new();
-
- if (status == 0) {
- srv_debug(1, xs_fmt("httpd_connection unattended %s %s", method, q_path));
- status = 404;
- }
- if (status == 404)
- body = xs_str_new("<h1>404 Not Found</h1>");
- if (status == 400)
- body = xs_str_new("<h1>400 Bad Request</h1>");
- if (status == 303)
- headers = xs_dict_append(headers, "location", body);
- if (status == 401)
- headers = xs_dict_append(headers, "WWW-Authenticate", "Basic realm=\"IDENTIFY\"");
- if (ctype == NULL)
- ctype = "text/html; charset=utf-8";
- headers = xs_dict_append(headers, "content-type", ctype);
- headers = xs_dict_append(headers, "x-creator", USER_AGENT);
- if (b_size == 0 && body != NULL)
- b_size = strlen(body);
-
- if (strcmp(method, "HEAD") == 0) {
- free(body);
- body = NULL;
- }
- xs_httpd_response(f, status, headers, body, b_size);
- fclose(f);
- srv_archive("RECV", req, payload, p_size, status, headers, body, b_size);
- free(body);
- }
- static jmp_buf on_break;
- void term_handler(int s)
- {
- longjmp(on_break, 1);
- }
- static void *purge_thread(void *arg)
- {
- srv_log(xs_dup("purge start"));
- purge_all();
- srv_log(xs_dup("purge end"));
- return NULL;
- }
- static void *queue_thread(void *arg)
- {
- pthread_mutex_t dummy_mutex = PTHREAD_MUTEX_INITIALIZER;
- pthread_cond_t dummy_cond = PTHREAD_COND_INITIALIZER;
- time_t purge_time;
-
- purge_time = time(NULL) + 15 * 60;
- srv_log(xs_fmt("queue thread start"));
- while (srv_running) {
- xs *list = user_list();
- char *p, *uid;
- time_t t;
-
- p = list;
- while (xs_list_iter(&p, &uid)) {
- snac snac;
- if (user_open(&snac, uid)) {
- process_queue(&snac);
- user_free(&snac);
- }
- }
-
- if ((t = time(NULL)) > purge_time) {
- pthread_t pth;
- pthread_create(&pth, NULL, purge_thread, NULL);
-
- purge_time = t + 24 * 60 * 60;
- }
-
- struct timespec ts;
- clock_gettime(CLOCK_REALTIME, &ts);
- ts.tv_sec += 3;
- pthread_mutex_lock(&dummy_mutex);
- while (pthread_cond_timedwait(&dummy_cond, &dummy_mutex, &ts) == 0);
- pthread_mutex_unlock(&dummy_mutex);
- }
- srv_log(xs_fmt("queue thread stop"));
- return NULL;
- }
- static void *connection_thread(void *arg)
- {
- httpd_connection((FILE *)arg);
- return NULL;
- }
- int threaded_connections = 1;
- void httpd(void)
- {
- char *address;
- int port;
- int rs;
- pthread_t htid;
- address = xs_dict_get(srv_config, "address");
- port = xs_number_get(xs_dict_get(srv_config, "port"));
- if ((rs = xs_socket_server(address, port)) == -1) {
- srv_log(xs_fmt("cannot bind socket to %s:%d", address, port));
- return;
- }
- srv_running = 1;
- signal(SIGPIPE, SIG_IGN);
- signal(SIGTERM, term_handler);
- signal(SIGINT, term_handler);
- srv_log(xs_fmt("httpd start %s:%d %s", address, port, USER_AGENT));
- pthread_create(&htid, NULL, queue_thread, NULL);
- if (setjmp(on_break) == 0) {
- for (;;) {
- FILE *f = xs_socket_accept(rs);
- if (threaded_connections) {
- pthread_t cth;
- pthread_create(&cth, NULL, connection_thread, f);
- }
- else
- httpd_connection(f);
- }
- }
- srv_running = 0;
-
- pthread_join(htid, NULL);
- srv_log(xs_fmt("httpd stop %s:%d", address, port));
- }
|