about summary refs log tree commit diff
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.gz
tipidee-00774b3f92bd6898ce56f41ce39074e9fe89c08e.tar.xz
tipidee-00774b3f92bd6898ce56f41ce39074e9fe89c08e.zip
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) ;
     }