-/*
- * This module sits directly above the HTTP layer. By the time we get here,
- * an HTTP request has been fully received and parsed. Control is passed up
- * to this layer to actually perform the request. We then fill in the response
- * and pass control back down to the HTTP layer to output the response back to
- * the client.
- *
- * Copyright (c) 1996-2018 by the citadel.org team
- *
- * This program is open source software; you can redistribute it and/or modify
- * it under the terms of the GNU General Public License version 3.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- * GNU General Public License for more details.
- */
+// This module sits directly above the HTTP layer. By the time we get here,
+// an HTTP request has been fully received and parsed. Control is passed up
+// to this layer to actually perform the request. We then fill in the response
+// and pass control back down to the HTTP layer to output the response back to
+// the client.
+//
+// Copyright (c) 1996-2022 by the citadel.org team
+//
+// This program is open source software. It runs great on the
+// Linux operating system (and probably elsewhere). You can use,
+// copy, and run it under the terms of the GNU General Public
+// License version 3.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
#include "webcit.h"
-/*
- * Not found! Wowzers.
- */
-void do_404(struct http_transaction *h)
-{
+// Not found! Wowzers.
+void do_404(struct http_transaction *h) {
h->response_code = 404;
h->response_string = strdup("NOT FOUND");
add_response_header(h, strdup("Content-type"), strdup("text/plain"));
}
-/*
- * Precondition failed (such as if-match)
- */
-void do_412(struct http_transaction *h)
-{
+// Precondition failed (such as if-match)
+void do_412(struct http_transaction *h) {
h->response_code = 412;
h->response_string = strdup("PRECONDITION FAILED");
}
-/*
- * We throw an HTTP error "502 bad gateway" when we need to connect to Citadel, but can't.
- */
-void do_502(struct http_transaction *h)
-{
+// We throw an HTTP error "502 bad gateway" when we need to connect to Citadel, but can't.
+void do_502(struct http_transaction *h) {
h->response_code = 502;
h->response_string = strdup("bad gateway");
add_response_header(h, strdup("Content-type"), strdup("text/plain"));
}
-/*
- * Tell the client to authenticate using HTTP-AUTH (RFC 2617)
- */
-void request_http_authenticate(struct http_transaction *h)
-{
+// Tell the client to authenticate using HTTP-AUTH (RFC 2617)
+void request_http_authenticate(struct http_transaction *h) {
h->response_code = 401;
h->response_string = strdup("Unauthorized");
add_response_header(h, strdup("WWW-Authenticate"), strdup("Basic realm=\"Citadel Server\""));
}
-/*
- * Easy and fun utility function to throw a redirect.
- */
-void http_redirect(struct http_transaction *h, char *to_where)
-{
+// Easy and fun utility function to throw a redirect.
+void http_redirect(struct http_transaction *h, char *to_where) {
syslog(LOG_DEBUG, "Redirecting to: %s", to_where);
h->response_code = 302;
h->response_string = strdup("Moved Temporarily");
}
-/*
- * perform_request() is the entry point for *every* HTTP transaction.
- */
-void perform_request(struct http_transaction *h)
-{
+// perform_request() is the entry point for *every* HTTP transaction.
+void perform_request(struct http_transaction *h) {
struct ctdlsession *c;
- // Determine which code path to take based on the beginning of the URI.
+ // Determine which code path to take based on the beginning of the URL.
// This is implemented as a series of strncasecmp() calls rather than a
// lookup table in order to make the code more readable.
- if (IsEmptyStr(h->uri))
- { // Sanity check
+ if (IsEmptyStr(h->url)) { // Sanity check
do_404(h);
return;
}
// with the /ctdl/ prefix.
// Root (/) ...
- if ( (!strcmp(h->uri, "/")) && (!strcasecmp(h->method, "GET")) )
- {
+ if ((!strcmp(h->url, "/")) && (!strcasecmp(h->method, "GET"))) {
http_redirect(h, "/ctdl/s/index.html");
return;
}
- // Legacy URI patterns (/readnew?gotoroom=xxx&start_reading_at=yyy) ...
+ // Legacy URL patterns (/readnew?gotoroom=xxx&start_reading_at=yyy) ...
// Direct room name (/my%20blog) ...
- // Everything below this line is strictly REST URI patterns.
+ // HTTP-01 challenge [RFC5785 section 3, RFC8555 section 9.2]
+ if (!strncasecmp(h->url, HKEY("/.well-known"))) { // Static content
+ output_static(h);
+ return;
+ }
- if (strncasecmp(h->uri, HKEY("/ctdl/")))
- { // Reject non-REST
+ if (!strcasecmp(h->url, "/favicon.ico")) {
+ output_static(h);
+ return;
+ }
+
+ // Everything below this line is strictly REST URL patterns.
+
+ if (strncasecmp(h->url, HKEY("/ctdl/"))) { // Reject non-REST
do_404(h);
return;
}
- if (!strncasecmp(h->uri, HKEY("/ctdl/s/")))
- { // Static content
+ if (!strncasecmp(h->url, HKEY("/ctdl/s/"))) { // Static content
output_static(h);
return;
}
- if (h->uri[7] != '/')
- {
+ if (h->url[7] != '/') {
do_404(h);
return;
}
// Anything below this line:
- // 1. Is in the format of /ctdl/?/*
- // 2. Requires a connection to a Citadel server.
+ // 1. Is in the format of /ctdl/?/*
+ // 2. Requires a connection to a Citadel server.
c = connect_to_citadel(h);
- if (c == NULL)
- {
+ if (c == NULL) {
do_502(h);
return;
}
// WebDAV methods like OPTIONS and PROPFIND *require* a logged-in session,
// even if the Citadel server allows anonymous access.
- if (IsEmptyStr(c->auth))
- {
- if ( (!strcasecmp(h->method, "OPTIONS"))
+ if (IsEmptyStr(c->auth)) {
+ if ( (!strcasecmp(h->method, "OPTIONS"))
|| (!strcasecmp(h->method, "PROPFIND"))
|| (!strcasecmp(h->method, "REPORT"))
|| (!strcasecmp(h->method, "DELETE"))
}
}
- // Break down the URI by path and send the request to the appropriate part of the program.
- //
- switch(h->uri[6])
- {
- case 'a': // /ctdl/a/ == RESTful path to admin functions
- ctdl_a(h, c);
- break;
- case 'c': // /ctdl/c/ == misc Citadel server commands
- ctdl_c(h, c);
- break;
- case 'r': // /ctdl/r/ == RESTful path to rooms
- ctdl_r(h, c);
- break;
- case 'u': // /ctdl/u/ == RESTful path to users
- do_404(h);
- break;
- default:
- do_404(h);
+ // Break down the URL by path and send the request to the appropriate part of the program.
+ switch (h->url[6]) {
+ case 'a': // /ctdl/a/ == RESTful path to admin functions
+ ctdl_a(h, c);
+ break;
+ case 'c': // /ctdl/c/ == misc Citadel server commands
+ ctdl_c(h, c);
+ break;
+ case 'f': // /ctdl/f/ == RESTful path to floors
+ ctdl_f(h, c);
+ break;
+ case 'r': // /ctdl/r/ == RESTful path to rooms
+ ctdl_r(h, c);
+ break;
+ case 'u': // /ctdl/u/ == RESTful path to users
+ ctdl_u(h, c);
+ break;
+ default:
+ do_404(h);
}
// Are we in an authenticated session? If so, set a cookie so we stay logged in.
- if (!IsEmptyStr(c->auth))
- {
+ if (!IsEmptyStr(c->auth)) {
char koekje[AUTH_MAX];
char *exp = http_datestring(time(NULL) + (86400 * 30));
- snprintf(koekje, AUTH_MAX, "wcauth=%s; path=/ctdl/; Expires=%s", c->auth, exp);
+ snprintf(koekje, AUTH_MAX, "wcauth=%s; path=/ctdl/; Expires=%s", c->auth, exp); // warn
free(exp);
add_response_header(h, strdup("Set-Cookie"), strdup(koekje));
}
- // During development we are foiling the browser cache completely. In production we'll be more selective.
+ // Durlng development we are foiling the browser cache completely. In production we'll be more selective.
add_response_header(h, strdup("Cache-Control"), strdup("no-store, must-revalidate"));
add_response_header(h, strdup("Pragma"), strdup("no-cache"));
add_response_header(h, strdup("Expires"), strdup("0"));