summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2023-09-30 09:38:18 +0000
committerLaurent Bercot <ska@appnovation.com>2023-09-30 09:38:18 +0000
commit00774b3f92bd6898ce56f41ce39074e9fe89c08e (patch)
treedeeb2a9b483ed3e4e637fc0ea744c65cc64d1763
parentf1a6903f46c0e2edcdd2b7fa83c8a5bb4ca0e021 (diff)
downloadtipidee-00774b3f92bd6898ce56f41ce39074e9fe89c08e.tar.xz
Some fixes; new SERVER_NAME source; prepare for more config
Signed-off-by: Laurent Bercot <ska@appnovation.com>
-rw-r--r--doc/tipideed.html31
-rw-r--r--src/libtipidee/tipidee_rql_read.c7
-rw-r--r--src/libtipidee/tipidee_uri_parse.c2
-rw-r--r--src/tipideed/cgi.c3
-rw-r--r--src/tipideed/tipideed-internal.h14
-rw-r--r--src/tipideed/tipideed.c91
6 files changed, 85 insertions, 63 deletions
diff --git a/doc/tipideed.html b/doc/tipideed.html
index 79c055b..2fa626a 100644
--- a/doc/tipideed.html
+++ b/doc/tipideed.html
@@ -138,14 +138,6 @@ operations itself.
<dd> The IP address the server is bound to. It will be passed as <tt>SERVER_ADDR</tt>
to CGI scripts. </dd>
- <dt> TCPLOCALPORT </dt>
- <dd> The port the server is bound to. It will be passed as <tt>SERVER_PORT</tt>
-to CGI scripts. </dd>
-
- <dt> TCPLOCALHOST </dt>
- <dd> The domain name associated to the local IP address. It will be
-passed as <tt>SERVER_NAME</tt> to CGI scripts. </dd>
-
<dt> TCPREMOTEIP </dt>
<dd> The IP address of the client. It will be passed as <tt>REMOTE_ADDR</tt>
to CGI scripts. </dd>
@@ -163,6 +155,19 @@ uses them to get more information.
</p>
<dl>
+ <dt> TCPLOCALHOST </dt>
+ <dd> The default domain name associated to the local IP address. It will be
+passed as <tt>SERVER_NAME</tt> to CGI scripts when the requested URI does
+not mention a Host, i.e. in HTTP/1.0 requests. If this variable is absent,
+the default will be set to the local IP address itself (between square
+brackets if IPv6). </dd>
+
+ <dt> TCPLOCALPORT </dt>
+ <dd> The port the server is bound to. It will be passed as <tt>SERVER_PORT</tt>
+to CGI scripts unless the requested URI explicitly mentions a different port.
+If this variable is absent, the default will be set to 80 in case of HTTP or
+443 in the case of HTTPS. </dd>
+
<dt> TCPREMOTEHOST </dt>
<dd> The domain name associated to the IP address of the client. It will
be passed as <tt>REMOTE_HOST</tt> to CGI scripts; if absent, the value of
@@ -377,11 +382,11 @@ it on its stdout, to the client. </li>
</ul> </li>
<li> tipideed exits on EOF (when the client closes the connection), or when
the client times out before sending a request, or after tipideed receives a
-single HTTP/1.0 request, or when it has answered a request with a
-<tt>Connection: close</tt> header, or when it encounters an error where it is
-likely that the client will have no use for the connection anymore anyway
-and exiting is simpler and cheaper &mdash; in which case tipideed adds
-<tt>Connection: close</tt> to its last answer. </li>
+single HTTP/1.0 request, or when it has executed into an NPH script, or when
+it has answered a request with a <tt>Connection: close</tt> header. It also
+exits when it encounters an error making it likely that the client will have
+no use for the connection anymore anyway and exiting is simpler and cheaper;
+in which case tipideed adds <tt>Connection: close</tt> to its last answer. </li>
</ul>
<div id="performance">
diff --git a/src/libtipidee/tipidee_rql_read.c b/src/libtipidee/tipidee_rql_read.c
index f3508cf..fc99f37 100644
--- a/src/libtipidee/tipidee_rql_read.c
+++ b/src/libtipidee/tipidee_rql_read.c
@@ -1,5 +1,6 @@
/* ISC license. */
+#include <errno.h>
#include <stdint.h>
#include <string.h>
#include <strings.h>
@@ -8,7 +9,6 @@
#include <skalibs/bytestr.h>
#include <skalibs/buffer.h>
#include <skalibs/unix-timed.h>
-// #include <skalibs/lolstdio.h>
#include <tipidee/method.h>
#include <tipidee/uri.h>
@@ -66,12 +66,11 @@ static inline int get_version (char const *in, tipidee_rql *rql)
int tipidee_rql_read (buffer *b, char *buf, size_t max, size_t *w, tipidee_rql *rql, tain const *deadline, tain *stamp)
{
size_t pos[3] = { 0 } ;
- if (timed_getlnmax(b, buf, max, &pos[0], '\n', deadline, stamp) <= 0) return -1 ;
+ if (timed_getlnmax(b, buf, max, &pos[0], '\n', deadline, stamp) == -1)
+ return errno == ETIMEDOUT ? 99 : -1 ;
buf[--pos[0]] = 0 ;
if (buf[pos[0] - 1] == '\r') buf[--pos[0]] = 0 ;
-// LOLDEBUG("tipidee_rql_read: timed_getlnmax: len is %zu, line is %s", pos[0], buf) ;
if (!rql_tokenize(buf, pos)) return 400 ;
-// LOLDEBUG("tipidee_rql_read: method: %s, version: %s, uri to parse: %s", buf + pos[0], buf + pos[2], buf + pos[1]) ;
rql->m = tipidee_method_tonum(buf + pos[0]) ;
if (rql->m == TIPIDEE_METHOD_UNKNOWN) return 400 ;
if (!get_version(buf + pos[2], rql)) return 400 ;
diff --git a/src/libtipidee/tipidee_uri_parse.c b/src/libtipidee/tipidee_uri_parse.c
index 10b0f91..6f0064a 100644
--- a/src/libtipidee/tipidee_uri_parse.c
+++ b/src/libtipidee/tipidee_uri_parse.c
@@ -154,7 +154,7 @@ size_t tipidee_uri_parse (char *out, size_t max, char const *in, tipidee_uri *ur
if (c & 0x4000) host = out + w ;
if (c & 0x2000) { if (w >= max) return 0 ; out[w++] = 0 ; }
if (c & 0x1000) mark = w ;
- if (c & 0x0800) { if (!uint160_scan(out + mark, &port)) return 0 ; w = mark ; }
+ if (c & 0x0800) { if (!uint160_scan(out + mark, &port) || !port) return 0 ; w = mark ; }
if (c & 0x0400) path = out + w ;
if (c & 0x0200) { if (w >= max) return 0 ; out[w++] = *in ; }
if (c & 0x0100) query = out + w ;
diff --git a/src/tipideed/cgi.c b/src/tipideed/cgi.c
index dc813c8..a875acd 100644
--- a/src/tipideed/cgi.c
+++ b/src/tipideed/cgi.c
@@ -65,6 +65,7 @@ static inline void modify_env (tipidee_rql const *rql, tipidee_headers const *hd
if (rql->uri.query) addenv(rql, "QUERY_STRING", rql->uri.query) ;
else delenv(rql, "QUERY_STRING") ;
addenv(rql, "SCRIPT_NAME", script) ;
+ addenv(rql, "SERVER_NAME", rql->uri.host) ;
for (size_t i = 0 ; i < hdr->n ; i++)
{
@@ -83,7 +84,7 @@ static inline void modify_env (tipidee_rql const *rql, tipidee_headers const *hd
}
}
else if (!strcasecmp(key, "Content-Type")) { addenv(rql, "CONTENT_TYPE", val) ; got |= 2 ; }
- else if (!strcasecmp(key, "Content-Length") || !strcasecmp(key, "Connection")) ;
+ else if (!strcasecmp(key, "Content-Length") || !strcasecmp(key, "Connection") || !strcasecmp(key, "Host")) ;
else
{
size_t len = strlen(key), pos = g.sa.len + 5 ;
diff --git a/src/tipideed/tipideed-internal.h b/src/tipideed/tipideed-internal.h
index 75f5be2..770596b 100644
--- a/src/tipideed/tipideed-internal.h
+++ b/src/tipideed/tipideed-internal.h
@@ -33,21 +33,22 @@ struct global_s
stralloc sa ;
size_t envlen ;
size_t localip ;
- size_t localhost ;
size_t localport ;
- size_t localportlen ;
+ size_t localhost ;
size_t remoteip ;
- size_t remotehost ;
size_t remoteport ;
+ size_t remotehost ;
size_t cwdlen ;
size_t indexlen ;
tain readtto ;
tain writetto ;
tain cgitto ;
+ char const *defaulthost ;
char const *indexnames[16] ;
int p[2] ;
uint32_t maxrqbody ;
uint32_t maxcgibody ;
+ uint16_t defaultport ;
uint16_t indexn : 4 ;
uint16_t verbosity : 3 ;
uint16_t cont : 2 ;
@@ -59,21 +60,22 @@ struct global_s
.sa = STRALLOC_ZERO, \
.envlen = 0, \
.localip = 0, \
- .localhost = 0, \
.localport = 0, \
- .localportlen = 0, \
+ .localhost = 0, \
.remoteip = 0, \
- .remotehost = 0, \
.remoteport = 0, \
+ .remotehost = 0, \
.cwdlen = 1, \
.indexlen = 0, \
.readtto = TAIN_ZERO, \
.writetto = TAIN_ZERO, \
.cgitto = TAIN_ZERO, \
+ .defaulthost = "@", \
.indexnames = { 0 }, \
.p = { -1, -1 }, \
.maxrqbody = 0, \
.maxcgibody = 0, \
+ .defaultport = 0, \
.indexn = 0, \
.verbosity = 1, \
.cont = 1, \
diff --git a/src/tipideed/tipideed.c b/src/tipideed/tipideed.c
index b5e1ea3..e7dd3a1 100644
--- a/src/tipideed/tipideed.c
+++ b/src/tipideed/tipideed.c
@@ -50,18 +50,20 @@ static inline void prep_env (void)
static char const basevars[] = "PROTO\0TCPCONNNUM\0GATEWAY_INTERFACE=CGI/1.1\0SERVER_PROTOCOL=HTTP/1.1\0SERVER_SOFTWARE=tipidee/" TIPIDEE_VERSION ;
static char const sslvars[] = "SSL_PROTOCOL\0SSL_CIPHER\0SSL_TLS_SNI_SERVERNAME\0SSL_PEER_CERT_HASH\0SSL_PEER_CERT_SUBJECT\0HTTPS=on" ;
char const *x = getenv("SSL_PROTOCOL") ;
- if (!stralloc_readyplus(&g.sa, 320)) dienomem() ;
+ size_t protolen ;
if (sagetcwd(&g.sa) == -1) strerr_diefu1sys(111, "getcwd") ;
if (g.sa.len == 1) g.sa.len = 0 ;
g.cwdlen = g.sa.len ;
- if (g.cwdlen && !stralloc_0(&g.sa)) dienomem() ;
- if (!stralloc_catb(&g.sa, basevars, sizeof(basevars))) dienomem() ;
- if (x && !stralloc_catb(&g.sa, sslvars, sizeof(sslvars))) dienomem() ;
+ if (!stralloc_readyplus(&g.sa, 220 + sizeof(basevars) + sizeof(sslvars))) dienomem() ;
+ if (g.cwdlen) stralloc_0(&g.sa) ;
+ stralloc_catb(&g.sa, basevars, sizeof(basevars)) ;
+ if (x) stralloc_catb(&g.sa, sslvars, sizeof(sslvars)) ;
g.ssl = !!x ;
x = getenv(basevars) ;
- if (!x) strerr_dienotset(100, "PROTO") ;
+ protolen = strlen(x) ;
+ if (protolen > 1000) strerr_dieinvalid(100, "PROTO") ;
+ if (!x) strerr_dienotset(100, "PROTO") ;
{
- size_t protolen = strlen(x) ;
size_t m ;
ip46 ip ;
uint16_t port ;
@@ -69,6 +71,16 @@ static inline void prep_env (void)
char var[protolen + 11] ;
memcpy(var, x, protolen) ;
+ memcpy(var + protolen, "LOCALPORT", 10) ;
+ x = getenv(var) ;
+ if (!x) strerr_dienotset(100, var) ;
+ if (!uint160_scan(x, &g.defaultport)) strerr_dieinvalid(100, var) ;
+ if (!stralloc_catb(&g.sa, var, protolen + 10)
+ || !stralloc_catb(&g.sa, "SERVER_PORT=", 12)) dienomem() ;
+ g.localport = g.sa.len ;
+ m = uint16_fmt(fmt, g.defaultport) ; fmt[m++] = 0 ;
+ if (!stralloc_catb(&g.sa, fmt, m)) dienomem() ;
+
memcpy(var + protolen, "LOCALIP", 8) ;
x = getenv(var) ;
if (!x) strerr_dienotset(100, var) ;
@@ -81,21 +93,21 @@ static inline void prep_env (void)
memcpy(var + protolen, "LOCALHOST", 10) ;
x = getenv(var) ;
- if (!x) strerr_dienotset(100, var) ;
- if (!stralloc_catb(&g.sa, var, protolen + 10)
- || !stralloc_catb(&g.sa, "SERVER_NAME=", 12)) dienomem() ;
- g.localhost = g.sa.len ;
- if (!stralloc_cats(&g.sa, x) || !stralloc_0(&g.sa)) dienomem() ;
+ if (x)
+ {
+ if (!stralloc_catb(&g.sa, var, protolen + 10)) dienomem() ;
+ g.defaulthost = x ;
+ }
- memcpy(var + protolen, "LOCALPORT", 10) ;
+ memcpy(var + protolen, "REMOTEPORT", 11) ;
x = getenv(var) ;
if (!x) strerr_dienotset(100, var) ;
if (!uint160_scan(x, &port)) strerr_dieinvalid(100, var) ;
- if (!stralloc_catb(&g.sa, var, protolen + 10)
- || !stralloc_catb(&g.sa, "SERVER_PORT=", 12)) dienomem() ;
- g.localport = g.sa.len ;
- g.localportlen = uint16_fmt(fmt, port) ; fmt[g.localportlen] = 0 ;
- if (!stralloc_catb(&g.sa, fmt, g.localportlen + 1)) dienomem() ;
+ if (!stralloc_catb(&g.sa, var, protolen + 11)
+ || !stralloc_catb(&g.sa, "REMOTE_PORT=", 12)) dienomem() ;
+ g.remoteport = g.sa.len ;
+ m = uint16_fmt(fmt, port) ; fmt[m++] = 0 ;
+ if (!stralloc_catb(&g.sa, fmt, m)) dienomem() ;
memcpy(var + protolen, "REMOTEIP", 9) ;
x = getenv(var) ;
@@ -112,18 +124,18 @@ static inline void prep_env (void)
if ((x && !stralloc_catb(&g.sa, var, protolen + 11))
|| !stralloc_catb(&g.sa, "REMOTE_HOST=", 12)) dienomem() ;
g.remotehost = g.sa.len ;
- if (!stralloc_cats(&g.sa, x ? x : fmt)
- || !stralloc_0(&g.sa)) dienomem() ;
-
- memcpy(var + protolen, "REMOTEPORT", 11) ;
- x = getenv(var) ;
- if (!x) strerr_dienotset(100, var) ;
- if (!uint160_scan(x, &port)) strerr_dieinvalid(100, var) ;
- if (!stralloc_catb(&g.sa, var, protolen + 11)
- || !stralloc_catb(&g.sa, "REMOTE_PORT=", 12)) dienomem() ;
- g.remoteport = g.sa.len ;
- m = uint16_fmt(fmt, port) ; fmt[m++] = 0 ;
- if (!stralloc_catb(&g.sa, fmt, m)) dienomem() ;
+ if (x)
+ {
+ if (!stralloc_cats(&g.sa, x)) dienomem() ;
+ }
+ else
+ {
+ if (!stralloc_readyplus(&g.sa, m + 2)) dienomem() ;
+ if (ip46_is6(&ip)) stralloc_catb(&g.sa, "[", 1) ;
+ stralloc_catb(&g.sa, g.sa.s + g.remoteip, m) ;
+ if (ip46_is6(&ip)) stralloc_catb(&g.sa, "]", 1) ;
+ }
+ if (!stralloc_0(&g.sa)) dienomem() ;
memcpy(var + protolen, "REMOTEINFO", 11) ;
x = getenv(var) ;
@@ -243,9 +255,10 @@ static inline void force_redirect (tipidee_rql const *rql, char const *fn)
respond_30x(rql, &rd) ;
}
-static inline int serve (tipidee_rql *rql, char const *docroot, size_t docrootlen, char *uribuf, tipidee_headers const *hdr, char const *body, size_t bodylen)
+static inline int serve (tipidee_rql *rql, char const *docroot, char *uribuf, tipidee_headers const *hdr, char const *body, size_t bodylen)
{
tipidee_resattr ra = TIPIDEE_RESATTR_ZERO ;
+ size_t docrootlen = strlen(docroot) ;
size_t pathlen = strlen(rql->uri.path) ;
char const *infopath = 0 ;
struct stat st ;
@@ -420,8 +433,9 @@ 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) ; /* Timeout, malicious client, or shitty client */
+ case -1 : log_and_exit(1) ; /* Malicious or shitty client */
case 0 : break ;
+ case 99 : g.cont = 0 ; continue ; /* timeout, it's ok */
case 400 : exit_400(&rql, "Syntax error in request line") ;
default : strerr_dief2x(101, "can't happen: ", "unknown tipidee_rql_read return code") ;
}
@@ -442,7 +456,7 @@ int main (int argc, char const *const *argv, char const *const *envp)
default : die500x(&rql, 101, "can't happen: ", "unknown tipidee_headers_parse return code") ;
}
- if (rql.http_minor == 0) g.cont = 0 ;
+ if (!rql.http_minor) g.cont = 0 ;
else
{
x = tipidee_headers_search(&hdr, "Connection") ;
@@ -490,7 +504,7 @@ int main (int argc, char const *const *argv, char const *const *envp)
default : die500x(&rql, 101, "can't happen: unknown HTTP method") ;
}
- if (!rql.uri.host)
+ if (rql.http_minor)
{
x = tipidee_headers_search(&hdr, "Host") ;
if (x)
@@ -504,17 +518,18 @@ int main (int argc, char const *const *argv, char const *const *envp)
if (!*x || *x == '.') exit_400(&rql, "Invalid Host header") ;
rql.uri.host = x ;
}
- else if (!rql.http_minor) rql.uri.host = "@" ;
- else exit_400(&rql, "Missing Host header") ;
+ else if (!rql.uri.host) exit_400(&rql, "Missing Host header") ;
}
+ else if (!rql.uri.host) rql.uri.host = g.defaulthost ;
+ if (!rql.uri.port) rql.uri.port = g.defaultport ;
{
size_t hostlen = strlen(rql.uri.host) ;
- char docroot[hostlen + g.localportlen + 2] ;
+ char docroot[hostlen + UINT16_FMT + 1] ;
if (rql.uri.host[hostlen - 1] == '.') hostlen-- ;
memcpy(docroot, rql.uri.host, hostlen) ;
docroot[hostlen] = ':' ;
- memcpy(docroot + hostlen + 1, g.sa.s + g.localport, g.localportlen + 1) ;
+ docroot[hostlen + 1 + uint16_fmt(docroot + hostlen + 1, rql.uri.port)] = 0 ;
/* All good. Read the body if any */
@@ -550,7 +565,7 @@ int main (int argc, char const *const *argv, char const *const *envp)
/* And serve the resource. The loop is in case of CGI local-redirection. */
- while (serve(&rql, docroot, hostlen + 1 + g.localportlen, uribuf, &hdr, bodysa.s, bodysa.len))
+ 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) ;
}