diff options
author | Laurent Bercot <ska-skaware@skarnet.org> | 2023-10-18 13:07:23 +0000 |
---|---|---|
committer | Laurent Bercot <ska@appnovation.com> | 2023-10-18 13:07:23 +0000 |
commit | 1a7e3d00588725da3d8764fa9d624bc8611be070 (patch) | |
tree | 65d28b52bd1d4ccdbeb418d4d681b1999ed46b7a /src/tipideed/tipideed.c | |
parent | 24fb88dbb023ae08adc9989bf19e0c6c569a6607 (diff) | |
download | tipidee-1a7e3d00588725da3d8764fa9d624bc8611be070.tar.xz |
Add infrastructure for custom error files
Signed-off-by: Laurent Bercot <ska@appnovation.com>
Diffstat (limited to 'src/tipideed/tipideed.c')
-rw-r--r-- | src/tipideed/tipideed.c | 106 |
1 files changed, 55 insertions, 51 deletions
diff --git a/src/tipideed/tipideed.c b/src/tipideed/tipideed.c index fb5ede4..b004782 100644 --- a/src/tipideed/tipideed.c +++ b/src/tipideed/tipideed.c @@ -45,7 +45,7 @@ static void sigchld_handler (int sig) wait_reap() ; } -static inline void log_and_exit (int e) +void log_and_exit (int e) { tipidee_log_exit(g.logv, e) ; _exit(e) ; @@ -164,7 +164,7 @@ static void inittto (tain *tto, char const *key) else *tto = tain_infinite_relative ; } -static inline unsigned int indexify (tipidee_rql const *rql, char *s, struct stat *st) +static inline unsigned int indexify (tipidee_rql const *rql, char const *docroot, char *s, struct stat *st) { unsigned int e = 0 ; size_t len = strlen(s) ; @@ -184,22 +184,22 @@ static inline unsigned int indexify (tipidee_rql const *rql, char *s, struct sta case ENAMETOOLONG : return 414 ; case ENOTDIR : return 404 ; case ENOENT : continue ; - default : die500sys(rql, 111, "stat ", s) ; + default : die500sys(rql, 111, docroot, "stat ", s) ; } } if (i >= g.indexn) return 404 ; - if (S_ISDIR(st->st_mode)) die500x(rql, 103, "bad document hierarchy: ", s, " is a directory") ; + if (S_ISDIR(st->st_mode)) die500x(rql, 102, docroot, "bad document hierarchy: ", s, " is a directory") ; if (e == 308) s[len] = 0 ; return e ; } -static inline void get_resattr (tipidee_rql const *rql, char const *res, tipidee_resattr *ra) +static inline void get_resattr (tipidee_rql const *rql, char const *docroot, char const *res, tipidee_resattr *ra) { static stralloc sa = STRALLOC_ZERO ; sa.len = 0 ; - if (sarealpath(&sa, res) == -1 || !stralloc_0(&sa)) die500sys(rql, 111, "realpath ", res) ; + if (sarealpath(&sa, res) == -1 || !stralloc_0(&sa)) die500sys(rql, 111, docroot, "realpath ", res) ; if (strncmp(sa.s, g.sa.s, g.cwdlen) || sa.s[g.cwdlen] != '/') - die500x(rql, 102, "resource ", res, " points outside of the server's root") ; + die500x(rql, 102, docroot, "resource ", res, " points outside of the server's root") ; { char const *attr = 0 ; @@ -211,7 +211,7 @@ static inline void get_resattr (tipidee_rql const *rql, char const *res, tipidee errno = ENOENT ; while (!attr) { - if (errno != ENOENT) die500x(rql, 102, "invalid configuration data for ", key) ; + if (errno != ENOENT) die500x(rql, 102, docroot, "invalid configuration data for ", key) ; while (len > 2 && key[len] != '/') len-- ; if (len <= 2) break ; key[len--] = 0 ; @@ -220,7 +220,7 @@ static inline void get_resattr (tipidee_rql const *rql, char const *res, tipidee } if (attr) { - if (*attr < '@' || *attr > 'G') die500x(rql, 102, "invalid configuration data for ", key) ; + if (*attr < '@' || *attr > 'G') die500x(rql, 102, docroot, "invalid configuration data for ", key) ; ra->iscgi = *attr & ~'@' & 1 ; if (attr[1]) ra->content_type = attr + 1 ; if (ra->iscgi) @@ -243,7 +243,7 @@ static inline void get_resattr (tipidee_rql const *rql, char const *res, tipidee if (!ra->iscgi && !ra->content_type) { ra->content_type = tipidee_conf_get_content_type(&g.conf, sa.s + g.cwdlen) ; - if (!ra->content_type) die500sys(rql, 111, "get content type for ", sa.s + g.cwdlen) ; + if (!ra->content_type) die500sys(rql, 111, docroot, "get content type for ", sa.s + g.cwdlen) ; } } @@ -276,7 +276,7 @@ static inline int serve (tipidee_rql *rql, char const *docroot, char *uribuf, ti { tipidee_redirection rd = TIPIDEE_REDIRECTION_ZERO ; int e = tipidee_conf_get_redirection(&g.conf, docroot, docrootlen, rql->uri.path, &rd) ; - if (e == -1) die500sys(rql, 111, "get redirection data for ", fn) ; + if (e == -1) die500sys(rql, 111, docroot, "get redirection data for ", fn) ; if (e) { respond_30x(rql, &rd) ; @@ -292,49 +292,49 @@ static inline int serve (tipidee_rql *rql, char const *docroot, char *uribuf, ti for (;;) { while (fn[pos] != '/') pos-- ; - if (pos <= docrootlen) { respond_404(rql) ; return 0 ; } + if (pos <= docrootlen) { respond_404(rql, docroot) ; return 0 ; } fn[pos] = 0 ; if (stat(fn, &st) == 0) break ; switch (errno) { case ENOTDIR : case ENOENT : fn[pos--] = '/' ; break ; - case EACCES : respond_403(rql) ; return 0 ; - case ENAMETOOLONG : respond_414(rql) ; return 0 ; - default : die500sys(rql, 111, "stat ", fn) ; + case EACCES : respond_403(rql, docroot) ; return 0 ; + case ENAMETOOLONG : respond_414(rql, docroot) ; return 0 ; + default : die500sys(rql, 111, docroot, "stat ", fn) ; } } infopath = fn + pos + 1 ; } if (S_ISDIR(st.st_mode)) { - if (infopath) { respond_404(rql) ; return 0 ; } - switch (indexify(rql, fn, &st)) + if (infopath) { respond_404(rql, docroot) ; return 0 ; } + switch (indexify(rql, docroot, fn, &st)) { - case 403 : respond_403(rql) ; return 0 ; - case 404 : respond_404(rql) ; return 0 ; - case 414 : respond_414(rql) ; return 0 ; + case 403 : respond_403(rql, docroot) ; return 0 ; + case 404 : respond_404(rql, docroot) ; return 0 ; + case 414 : respond_414(rql, docroot) ; return 0 ; case 308 : force_redirect(rql, fn) ; return 0 ; case 0 : break ; } } - LOLDEBUG("serve: %s with %s %s, docroot %s", fn, infopath ? "infopath" : "no", infopath ? infopath : "infopath", docroot) ; + tipidee_log_debug(g.logv, "serve: docroot ", docroot, " file ", fn, " infopath ", infopath ? infopath : "(none)") ; - get_resattr(rql, fn, &ra) ; + get_resattr(rql, docroot, fn, &ra) ; if (!ra.iscgi) { - if (infopath) { respond_404(rql) ; return 0 ; } - if (rql->m == TIPIDEE_METHOD_POST) exit_405(rql, 0) ; + if (infopath) { respond_404(rql, docroot) ; return 0 ; } + if (rql->m == TIPIDEE_METHOD_POST) exit_405(rql) ; } if (rql->m == TIPIDEE_METHOD_OPTIONS) return respond_options(rql, 2 | ra.iscgi) ; - tipidee_log_resource(g.logv, rql, docroot, fn, &ra) ; + tipidee_log_resource(g.logv, rql, fn, &ra, infopath) ; if (ra.iscgi) - return respond_cgi(rql, fn, docrootlen, infopath, uribuf, hdr, &ra, body, bodylen) ; + return respond_cgi(rql, docroot, fn, docrootlen, infopath, uribuf, hdr, &ra, body, bodylen) ; infopath = tipidee_headers_search(hdr, "If-Modified-Since") ; if (infopath) @@ -345,7 +345,7 @@ static inline int serve (tipidee_rql *rql, char const *docroot, char *uribuf, ti && tain_less(&actual, &wanted)) return respond_304(rql, fn, &st) ; } - return respond_regular(rql, fn, &st, &ra) ; + return respond_regular(rql, docroot, fn, &st, &ra) ; } int main (int argc, char const *const *argv, char const *const *envp) @@ -403,6 +403,8 @@ int main (int argc, char const *const *argv, char const *const *envp) init_splice_pipe() ; if (!sig_catch(SIGCHLD, &sigchld_handler)) strerr_diefu1sys(111, "set SIGCHLD handler") ; + if (!sig_altignore(SIGPIPE)) + strerr_diefu1sys(111, "ignore SIGPIPE") ; if (!tain_now_set_stopwatch_g()) strerr_diefu1sys(111, "initialize clock") ; tipidee_log_start(g.logv, g.sa.s + remoteip, g.sa.s + remotehost) ; @@ -430,14 +432,15 @@ int main (int argc, char const *const *argv, char const *const *envp) e = tipidee_rql_read_g(buffer_0, uribuf, URI_BUFSIZE, &content_length, &rql, &deadline) ; switch (e) { - case -1 : log_and_exit(1) ; /* Malicious or shitty client */ + case -1 : log_and_exit(1) ; /* bad client */ case 0 : break ; - case 99 : g.cont = 0 ; continue ; /* timeout, it's ok */ - case 400 : preexit_400(&rql, "Syntax error in request line") ; + case 98 : /* client exited */ + case 99 : g.cont = 0 ; continue ; /* timeout */ + case 400 : eexit_400(&rql, "Syntax error in request line") ; default : strerr_dief2x(101, "can't happen: ", "unknown tipidee_rql_read return code") ; } if (rql.http_major != 1) log_and_exit(1) ; - if (rql.http_minor > 1) preexit_400(&rql, "Bad HTTP version") ; + if (rql.http_minor > 1) eexit_400(&rql, "Bad HTTP version") ; content_length = 0 ; tipidee_headers_init(&hdr, hdrbuf, HDR_BUFSIZE) ; @@ -446,9 +449,9 @@ int main (int argc, char const *const *argv, char const *const *envp) { case -1 : log_and_exit(1) ; /* connection issue, client timeout, etc. */ case 0 : break ; - case 400 : preexit_400(&rql, "Syntax error in headers") ; - case 408 : preexit_408(&rql) ; /* timeout */ - case 413 : preexit_413(&rql, hdr.n >= TIPIDEE_HEADERS_MAX ? "Too many headers" : "Too much header data") ; + case 400 : eexit_400(&rql, "Syntax error in headers") ; + case 408 : eexit_408(&rql) ; /* timeout */ + case 413 : eexit_413(&rql, hdr.n >= TIPIDEE_HEADERS_MAX ? "Too many headers" : "Too much header data") ; case 500 : strerr_dief2x(101, "can't happen: ", "avltreen_insert failed") ; default : strerr_dief2x(101, "can't happen: ", "unknown tipidee_headers_parse return code") ; } @@ -467,7 +470,7 @@ int main (int argc, char const *const *argv, char const *const *envp) x = tipidee_headers_search(&hdr, "Transfer-Encoding") ; if (x) { - if (strcasecmp(x, "chunked")) preexit_400(&rql, "unsupported Transfer-Encoding") ; + if (strcasecmp(x, "chunked")) eexit_400(&rql, "unsupported Transfer-Encoding") ; else tcoding = TIPIDEE_TRANSFERCODING_CHUNKED ; } else @@ -475,7 +478,7 @@ int main (int argc, char const *const *argv, char const *const *envp) x = tipidee_headers_search(&hdr, "Content-Length") ; if (x) { - if (!size_scan(x, &content_length)) preexit_400(&rql, "Invalid Content-Length") ; + if (!size_scan(x, &content_length)) eexit_400(&rql, "Invalid Content-Length") ; else if (content_length) tcoding = TIPIDEE_TRANSFERCODING_FIXED ; else tcoding = TIPIDEE_TRANSFERCODING_NONE ; } @@ -483,7 +486,7 @@ int main (int argc, char const *const *argv, char const *const *envp) } if (tcoding != TIPIDEE_TRANSFERCODING_NONE && rql.m != TIPIDEE_METHOD_POST) - preexit_400(&rql, "only POST requests can have an entity body") ; + eexit_400(&rql, "only POST requests can have an entity body") ; switch (rql.m) { @@ -495,9 +498,9 @@ int main (int argc, char const *const *argv, char const *const *envp) if (!rql.uri.path) { respond_options(&rql, 1) ; continue ; } break ; case TIPIDEE_METHOD_PUT : - case TIPIDEE_METHOD_DELETE : exit_405(&rql, 3) ; - case TIPIDEE_METHOD_CONNECT : preexit_501(&rql, "CONNECT method unsupported") ; - case TIPIDEE_METHOD_PRI : preexit_501(&rql, "PRI method attempted with HTTP version 1") ; + case TIPIDEE_METHOD_DELETE : eexit_405(&rql) ; + case TIPIDEE_METHOD_CONNECT : eexit_501(&rql, "CONNECT method unsupported") ; + case TIPIDEE_METHOD_PRI : eexit_501(&rql, "PRI method attempted with HTTP version 1") ; default : strerr_dief2x(101, "can't happen: ", "unknown HTTP method") ; } @@ -509,13 +512,13 @@ int main (int argc, char const *const *argv, char const *const *envp) char *p = strchr(x, ':') ; if (p) { - if (!uint160_scan(p+1, &rql.uri.port)) preexit_400(&rql, "Invalid Host header") ; + if (!uint160_scan(p+1, &rql.uri.port)) eexit_400(&rql, "Invalid Host header") ; *p = 0 ; } - if (!*x || *x == '.') preexit_400(&rql, "Invalid Host header") ; + if (!*x || *x == '.') eexit_400(&rql, "Invalid Host header") ; rql.uri.host = x ; } - else if (!rql.uri.host) preexit_400(&rql, "Missing Host header") ; + else if (!rql.uri.host) eexit_400(&rql, "Missing Host header") ; } else if (!rql.uri.host) rql.uri.host = g.defaulthost ; if (!rql.uri.port) rql.uri.port = g.defaultport ; @@ -541,12 +544,12 @@ int main (int argc, char const *const *argv, char const *const *envp) { case TIPIDEE_TRANSFERCODING_FIXED : { - if (content_length > g.maxrqbody) exit_413(&rql, "Request body too large") ; - if (!stralloc_ready(&bodysa, content_length)) die500sys(&rql, 111, "stralloc_ready") ; + if (content_length > g.maxrqbody) exit_413(&rql, docroot) ; + if (!stralloc_ready(&bodysa, content_length)) die500sys(&rql, 111, docroot, "stralloc_ready") ; if (buffer_timed_get_g(buffer_0, bodysa.s, content_length, &deadline) < content_length) { - if (errno == ETIMEDOUT) exit_408(&rql) ; - else exit_400(&rql, "Request body does not match Content-Length") ; + if (errno == ETIMEDOUT) exit_408(&rql, docroot) ; + else exit_400(&rql, docroot) ; } bodysa.len = content_length ; break ; @@ -555,9 +558,9 @@ int main (int argc, char const *const *argv, char const *const *envp) { if (!tipidee_util_chunked_read_g(buffer_0, &bodysa, g.maxrqbody, &deadline)) { - if (error_temp(errno)) die500sys(&rql, 111, "decode chunked body") ; - else if (errno == EMSGSIZE) exit_413(&rql, "Request body too large") ; - else exit_400(&rql, "Invalid chunked body") ; + if (error_temp(errno)) die500sys(&rql, 111, docroot, "decode chunked body") ; + else if (errno == EMSGSIZE) exit_413(&rql, docroot) ; + else exit_400(&rql, docroot) ; } break ; } @@ -569,8 +572,9 @@ int main (int argc, char const *const *argv, char const *const *envp) while (serve(&rql, docroot, uribuf, &hdr, bodysa.s, bodysa.len)) if (localredirs++ >= MAX_LOCALREDIRS) - die502x(&rql, 2, "too many local redirections - possible loop involving path ", rql.uri.path) ; + die502x(&rql, 2, docroot, "too many local redirections - possible loop involving path ", rql.uri.path) ; } } + log_and_exit(0) ; } |