X-Git-Url: https://unix4lyfe.org/gitweb/darkstat-debian/blobdiff_plain/85d7d6e7b81dff84df8ddc87815ce77b8d82bc07..3c6b3682c70be84db86e70c191016913a9836c31:/http.c diff --git a/http.c b/http.c index e39f16b..0cd6133 100644 --- a/http.c +++ b/http.c @@ -1,5 +1,5 @@ /* darkstat 3 - * copyright (c) 2001-2012 Emil Mikulic. + * copyright (c) 2001-2014 Emil Mikulic. * * http.c: embedded webserver. * This borrows a lot of code from darkhttpd. @@ -37,6 +37,9 @@ #include #include +static char *http_base_url = NULL; +static int http_base_len = 0; + static const char mime_type_xml[] = "text/xml"; static const char mime_type_html[] = "text/html; charset=us-ascii"; static const char mime_type_css[] = "text/css"; @@ -56,7 +59,7 @@ struct connection { int socket; struct sockaddr_storage client; - long last_active_mono; + time_t last_active_mono; enum { RECV_REQUEST, /* receiving request */ SEND_HEADER_AND_REPLY, /* try to send header+reply together */ @@ -381,23 +384,28 @@ static void generate_header(struct connection *conn, if (conn->encoding == NULL) conn->encoding = encoding_identity; - verbosef("http: %d %s (%s: %zu bytes)", code, text, - conn->encoding, conn->reply_length); + verbosef("http: %d %s (%s: %zu bytes)", + code, + text, + conn->encoding, + conn->reply_length); conn->header_length = xasprintf(&(conn->header), "HTTP/1.1 %d %s\r\n" "Date: %s\r\n" "Server: %s\r\n" "Vary: Accept-Encoding\r\n" "Content-Type: %s\r\n" - "Content-Length: %d\r\n" + "Content-Length: %qu\r\n" "Content-Encoding: %s\r\n" "X-Robots-Tag: noindex, noarchive\r\n" "%s" - "\r\n" - , + "\r\n", code, text, - rfc1123_date(date, now_real()), server, - conn->mime_type, conn->reply_length, conn->encoding, + rfc1123_date(date, now_real()), + server, + conn->mime_type, + (qu)conn->reply_length, + conn->encoding, conn->header_extra); conn->http_code = code; } @@ -407,6 +415,9 @@ static void generate_header(struct connection *conn, /* --------------------------------------------------------------------------- * A default reply for any (erroneous) occasion. */ +static void default_reply(struct connection *conn, + const int errcode, const char *errname, const char *format, ...) + _printflike_(4, 5); static void default_reply(struct connection *conn, const int errcode, const char *errname, const char *format, ...) { @@ -571,11 +582,16 @@ process_gzip(struct connection *conn) zs.zfree = Z_NULL; zs.opaque = Z_NULL; - if (deflateInit2(&zs, Z_BEST_COMPRESSION, Z_DEFLATED, - 15+16, /* 15 = biggest window, 16 = add gzip header+trailer */ - 8 /* default */, - Z_DEFAULT_STRATEGY) != Z_OK) - return; + if (deflateInit2(&zs, + Z_BEST_COMPRESSION, + Z_DEFLATED, + 15+16, /* 15 = biggest window, + 16 = add gzip header+trailer */ + 8 /* default */, + Z_DEFAULT_STRATEGY) != Z_OK) { + free(buf); + return; + } zs.avail_in = conn->reply_length; zs.next_in = (unsigned char *)conn->reply; @@ -586,7 +602,7 @@ process_gzip(struct connection *conn) if (deflate(&zs, Z_FINISH) != Z_STREAM_END) { deflateEnd(&zs); free(buf); - verbosef("failed to compress %u bytes", (unsigned int)len); + verbosef("failed to compress %zu bytes", len); return; } @@ -605,22 +621,32 @@ process_gzip(struct connection *conn) */ static void process_get(struct connection *conn) { - char *decoded_url, *safe_url; + char *safe_url; verbosef("http: %s \"%s\" %s", conn->method, conn->uri, (conn->query == NULL)?"":conn->query); - /* work out path of file being requested */ - decoded_url = urldecode(conn->uri); - - /* make sure it's safe */ - safe_url = make_safe_uri(decoded_url); - free(decoded_url); - if (safe_url == NULL) { - default_reply(conn, 400, "Bad Request", - "You requested an invalid URI: %s", conn->uri); - return; + /* Decode the URL being requested. */ + char *decoded_url; + char *decoded_url_offset; + + decoded_url = urldecode(conn->uri); + + /* Optionally strip the base. */ + decoded_url_offset = decoded_url; + if (str_starts_with(decoded_url, http_base_url)) { + decoded_url_offset += http_base_len - 1; + } + + /* Make sure it's safe. */ + safe_url = make_safe_uri(decoded_url_offset); + free(decoded_url); + if (safe_url == NULL) { + default_reply(conn, 400, "Bad Request", + "You requested an invalid URI: %s", conn->uri); + return; + } } if (strcmp(safe_url, "/") == 0) { @@ -873,6 +899,40 @@ static void poll_send_reply(struct connection *conn) if (conn->reply_sent == conn->reply_length) conn->state = DONE; } + + +/* -------------------------------------------------------------------------- + * Initialize the base url. + */ +void http_init_base(const char *url) { + char *slashed_url, *safe_url; + size_t urllen; + + if (url == NULL) { + http_base_url = strdup("/"); + } else { + /* Make sure that the url has leading and trailing slashes. */ + urllen = strlen(url); + slashed_url = xmalloc(urllen+3); + slashed_url[0] = '/'; + memcpy(slashed_url+1, url, urllen); /* don't copy NUL */ + slashed_url[urllen+1] = '/'; + slashed_url[urllen+2] = '\0'; + + /* Clean the url. */ + safe_url = make_safe_uri(slashed_url); + free(slashed_url); + if (safe_url == NULL) { + verbosef("invalid base \"%s\", ignored", url); + http_base_url = strdup("/"); /* set to default */ + } else { + http_base_url = safe_url; + } + } + http_base_len = strlen(http_base_url); + verbosef("set base url to \"%s\"", http_base_url); +} + /* Use getaddrinfo to figure out what type of socket to create and * what to bind it to. "bindaddr" can be NULL. Remember to freeaddrinfo() * the result. @@ -962,11 +1022,12 @@ static void http_listen_one(struct addrinfo *ai, if (listen(sockin, 128) == -1) err(1, "listen() failed"); - verbosef("listening on http://%s%s%s:%u/", + verbosef("listening on http://%s%s%s:%u%s", (ai->ai_family == AF_INET6) ? "[" : "", ipaddr, (ai->ai_family == AF_INET6) ? "]" : "", - bindport); + bindport, + http_base_url); /* add to insocks */ insocks = xrealloc(insocks, sizeof(*insocks) * (insock_num + 1)); @@ -1122,6 +1183,8 @@ void http_stop(void) { struct connection *conn; unsigned int i; + free(http_base_url); + /* Close listening sockets. */ for (i=0; i