about summary refs log tree commit diff
diff options
context:
space:
mode:
authorLaurent Bercot <ska-skaware@skarnet.org>2023-08-29 16:30:15 +0000
committerLaurent Bercot <ska@appnovation.com>2023-08-29 16:30:15 +0000
commit0691bcbd11897694a604f99fa58af6b4286c7195 (patch)
treea5259e0b1118c5d294cb4bfb77fa3d25fed4d121
parente6ada0b74352f77124a682d98c6d842fd5c44b45 (diff)
downloadtipidee-0691bcbd11897694a604f99fa58af6b4286c7195.tar.gz
tipidee-0691bcbd11897694a604f99fa58af6b4286c7195.tar.xz
tipidee-0691bcbd11897694a604f99fa58af6b4286c7195.zip
More examples, some fixes, some more doc
Signed-off-by: Laurent Bercot <ska@appnovation.com>
-rw-r--r--doc/quickstart.html38
-rw-r--r--etc/tipidee.conf61
-rwxr-xr-xexamples/s6-rc/httpd-6-log/run2
-rw-r--r--examples/s6/httpd-4/log/notification-fd1
-rwxr-xr-xexamples/s6/httpd-4/log/run5
-rw-r--r--examples/s6/httpd-4/notification-fd1
-rwxr-xr-xexamples/s6/httpd-4/run10
-rw-r--r--examples/s6/httpd-6/log/notification-fd1
-rwxr-xr-xexamples/s6/httpd-6/log/run5
-rw-r--r--examples/s6/httpd-6/notification-fd1
-rwxr-xr-xexamples/s6/httpd-6/run10
-rw-r--r--examples/s6/httpsd-4/log/notification-fd1
-rwxr-xr-xexamples/s6/httpsd-4/log/run5
-rw-r--r--examples/s6/httpsd-4/notification-fd1
-rwxr-xr-xexamples/s6/httpsd-4/run11
-rw-r--r--examples/s6/httpsd-6/log/notification-fd1
-rwxr-xr-xexamples/s6/httpsd-6/log/run5
-rw-r--r--examples/s6/httpsd-6/notification-fd1
-rwxr-xr-xexamples/s6/httpsd-6/run11
-rw-r--r--examples/tipidee.conf84
-rw-r--r--src/config/lexparse.c4
-rw-r--r--src/config/tipidee-config-internal.h2
-rw-r--r--src/config/tipidee-config-preprocess.c4
-rw-r--r--src/config/tipidee-config.c7
-rw-r--r--src/tipideed/tipideed.c6
25 files changed, 178 insertions, 100 deletions
diff --git a/doc/quickstart.html b/doc/quickstart.html
index 4b369eb..974c4b5 100644
--- a/doc/quickstart.html
+++ b/doc/quickstart.html
@@ -25,16 +25,16 @@
  <a href="//skarnet.org/software/s6-networking/">s6-networking</a> installed
 alongside tipidee. </li>
  <li> Prepare your document root for every virtual domain you aim to serve.
-For instance, if your documents are in <tt>/home/www</tt> and you need to
+For instance, if your documents are in <tt>/home/www/docs</tt> and you need to
 serve the <tt>example.com</tt> and <tt>example.org</tt> domains, create
-<tt>/home/www/example.com</tt> and <tt>/home/www/example.org</tt> directories,
+<tt>/home/www/docs/example.com</tt> and <tt>/home/www/docs/example.org</tt> directories,
 they will be the document roots for the <tt>example.com</tt> and <tt>example.org</tt>
 virtual sites respectively. </li>
  <li> Symlink these canonical directories to all the <em>host:port</em> combinations
 you want them to be available on. If you want <tt>example.com</tt> and
 <tt>example.org</tt> to be both available on ports 80 and 443, then symlink
 <tt>example.com</tt> to <tt>example.com:80</tt> and <tt>example.com:443</tt>
-in the <tt>/home/www</tt> directory, and do the same with <tt>example.org</tt>. </li>
+in the <tt>/home/www/docs</tt> directory, and do the same with <tt>example.org</tt>. </li>
  <li> Compile a default configuration for tipidee:
 <tt>:&gt; /etc/tipidee.conf &amp;&amp; tipidee-config</tt>.
   <ul>
@@ -103,5 +103,37 @@ your service manager scripts. </li>
 containing service files to run tipidee under various service managers. 
 </p>
 
+<div id="faq">
+<h2> Frequently asked questions </h2>
+</div>
+
+<h3> I want my web server to listen to more than one address. Do I need
+to do all that for every address I have? </h3>
+
+<p>
+ Not necessarily: you could listen to <tt>0.0.0.0</tt> for IPv4, and
+<tt>::</tt> for IPv6. But if you don't want your server to listen to
+<em>all</em> the addresses on your machine, then yes, you will have
+to run one process per address:port tuple.
+</p>
+
+<p>
+ It's okay though: every listening process is very small. The skarnet.org
+server has two network cards and runs a web server on both of them, on
+IPv4 and IPv6, over HTTP and HTTPS, which makes 8 services. Plus one
+<a href="//skarnet.org/software/s6/s6-log.html">s6-log</a> logger process
+for each of these services. Plus a supervisor for every service and every
+logger &mdash; for a whooping total of 64 long-running processes just for
+its web server functionality; and it's still not even noticeable, the
+amount of resources it consumes is negligible. So, don't worry about it.
+</p>
+
+<p>
+ Note that this allows you to run different instances of
+<a href="tipideed.html">tipideed</a> with different configurations, if
+you need it. Use the <tt>-f</tt> option to specify a different config
+file for <a href="tipideed.html">tipideed</a>.
+</p>
+
 </body>
 </html>
diff --git a/etc/tipidee.conf b/etc/tipidee.conf
deleted file mode 100644
index cbbfac6..0000000
--- a/etc/tipidee.conf
+++ /dev/null
@@ -1,61 +0,0 @@
-# tipideed verbosity (overridden by the -v option).
-# 0 is quiet, 1 is normal, 2+ is verbose.
-# global verbosity 1
-
-# tipideed will exit if the client does not send a new request
-# after N milliseconds.
-# 0 means no timeout.
-# global read_timeout 0
-
-# tipideed will drop the connection if the client
-# does not read answers for N milliseconds.
-# 0 means no timeout.
-# global write_timeout 0
-
-# tipideed will answer 504 ("Gateway Timeout") if a CGI program
-# (including NPH) does not complete in N milliseconds.
-# 0 means no timeout.
-# global cgi_timeout 0
-
-# tipideed will refuse to serve POST requests if the client-
-# provided data is larger than N bytes.
-# global max_request_body_length 8192
-
-# tipideed will answer 502 ("Bad Gateway") if a CGI script's answer
-# is larger than N bytes. (does not apply to NPH scripts)
-# global max_cgi_body_length 4194304
-
-# When the requested URL is a directory, tipideed will serve the first
-# existing file in this list. (Useful e.g. if you have an index.cgi program.)
-# global index_file index.html
-
-# You can define your own Content-Type mappings by file extension.
-# The default mappings should work well for most servers.
-# content-type text/html .html .htm
-
-
-# The domain to which the next directives apply.
-# You need one domain directive for each of the domains you serve,
-# domain example.com
-
-# If a CGI script under the current domain starts with this prefix,
-# it will be considered a NPH script (non-parsable headers).
-# nph-prefix nph-
-
-# If uncommented: every file under that directory will be considered
-# a CGI script.
-# cgi /cgi-bin/
-
-# You can also declare that individual files are CGI scripts.
-# cgi /index.cgi
-
-# If uncommented: every CGI script under that directory will be considered NPH.
-# nph /cgi-bin/nph/
-
-# You can also declare that individual scripts are NPH.
-# nph /cgi-bin/basic.cgi
-
-# You can override the default Content-Type for individual files,
-# no matter what extension they have.
-# file-type /source/document.html text/plain
-
diff --git a/examples/s6-rc/httpd-6-log/run b/examples/s6-rc/httpd-6-log/run
index 50d7448..5889b3e 100755
--- a/examples/s6-rc/httpd-6-log/run
+++ b/examples/s6-rc/httpd-6-log/run
@@ -2,4 +2,4 @@
 
 s6-setuidgid wwwlog
 exec -c
-s6-log -d3 t s1000000 n20 /var/log/httpd-46
+s6-log -d3 t s1000000 n20 /var/log/httpd-6
diff --git a/examples/s6/httpd-4/log/notification-fd b/examples/s6/httpd-4/log/notification-fd
new file mode 100644
index 0000000..00750ed
--- /dev/null
+++ b/examples/s6/httpd-4/log/notification-fd
@@ -0,0 +1 @@
+3
diff --git a/examples/s6/httpd-4/log/run b/examples/s6/httpd-4/log/run
new file mode 100755
index 0000000..51897c7
--- /dev/null
+++ b/examples/s6/httpd-4/log/run
@@ -0,0 +1,5 @@
+#!/bin/execlineb -S1
+
+s6-setuidgid wwwlog
+exec -c
+s6-log -d3 t s1000000 n20 /var/log/httpd-4
diff --git a/examples/s6/httpd-4/notification-fd b/examples/s6/httpd-4/notification-fd
new file mode 100644
index 0000000..00750ed
--- /dev/null
+++ b/examples/s6/httpd-4/notification-fd
@@ -0,0 +1 @@
+3
diff --git a/examples/s6/httpd-4/run b/examples/s6/httpd-4/run
new file mode 100755
index 0000000..190392f
--- /dev/null
+++ b/examples/s6/httpd-4/run
@@ -0,0 +1,10 @@
+#!/bin/execlineb -P
+
+fdmove -c 2 1
+backtick -E ip { pipeline { s6-dnsip4 example.com } head -n 1 }
+s6-envuidgid www
+cd /home/www
+fdmove 1 3
+s6-tcpserver4 -v2 -1 -U -c 512 -- $ip 80
+s6-tcpserver-access -lexample.com --
+tipideed -v2 --
diff --git a/examples/s6/httpd-6/log/notification-fd b/examples/s6/httpd-6/log/notification-fd
new file mode 100644
index 0000000..00750ed
--- /dev/null
+++ b/examples/s6/httpd-6/log/notification-fd
@@ -0,0 +1 @@
+3
diff --git a/examples/s6/httpd-6/log/run b/examples/s6/httpd-6/log/run
new file mode 100755
index 0000000..5889b3e
--- /dev/null
+++ b/examples/s6/httpd-6/log/run
@@ -0,0 +1,5 @@
+#!/bin/execlineb -S1
+
+s6-setuidgid wwwlog
+exec -c
+s6-log -d3 t s1000000 n20 /var/log/httpd-6
diff --git a/examples/s6/httpd-6/notification-fd b/examples/s6/httpd-6/notification-fd
new file mode 100644
index 0000000..00750ed
--- /dev/null
+++ b/examples/s6/httpd-6/notification-fd
@@ -0,0 +1 @@
+3
diff --git a/examples/s6/httpd-6/run b/examples/s6/httpd-6/run
new file mode 100755
index 0000000..ae4dbba
--- /dev/null
+++ b/examples/s6/httpd-6/run
@@ -0,0 +1,10 @@
+#!/bin/execlineb -P
+
+fdmove -c 2 1
+backtick -E ip { pipeline { s6-dnsip6 example.com } head -n 1 }
+s6-envuidgid www
+cd /home/www
+fdmove 1 3
+s6-tcpserver6 -v2 -1 -U -c 512 -- $ip 80
+s6-tcpserver-access -lexample.com --
+tipideed -v2 --
diff --git a/examples/s6/httpsd-4/log/notification-fd b/examples/s6/httpsd-4/log/notification-fd
new file mode 100644
index 0000000..00750ed
--- /dev/null
+++ b/examples/s6/httpsd-4/log/notification-fd
@@ -0,0 +1 @@
+3
diff --git a/examples/s6/httpsd-4/log/run b/examples/s6/httpsd-4/log/run
new file mode 100755
index 0000000..770d831
--- /dev/null
+++ b/examples/s6/httpsd-4/log/run
@@ -0,0 +1,5 @@
+#!/bin/execlineb -S1
+
+s6-setuidgid wwwlog
+exec -c
+s6-log -d3 t s1000000 n20 /var/log/httpsd-4
diff --git a/examples/s6/httpsd-4/notification-fd b/examples/s6/httpsd-4/notification-fd
new file mode 100644
index 0000000..00750ed
--- /dev/null
+++ b/examples/s6/httpsd-4/notification-fd
@@ -0,0 +1 @@
+3
diff --git a/examples/s6/httpsd-4/run b/examples/s6/httpsd-4/run
new file mode 100755
index 0000000..54be026
--- /dev/null
+++ b/examples/s6/httpsd-4/run
@@ -0,0 +1,11 @@
+#!/bin/execlineb -P
+
+fdmove -c 2 1
+backtick -E ip { pipeline { s6-dnsip4 example.com } head -n 1 }
+s6-envuidgid www
+export KEYFILE /etc/ssl/acme/private/example.com/key.pem
+export CERTFILE /etc/ssl/acme/example.com/cert.pem
+cd /home/www
+fdmove 1 3
+s6-tlsserver -v -4 -1 -U -c 512 -K 30000 -- $ip 443
+tipideed -v2 --
diff --git a/examples/s6/httpsd-6/log/notification-fd b/examples/s6/httpsd-6/log/notification-fd
new file mode 100644
index 0000000..00750ed
--- /dev/null
+++ b/examples/s6/httpsd-6/log/notification-fd
@@ -0,0 +1 @@
+3
diff --git a/examples/s6/httpsd-6/log/run b/examples/s6/httpsd-6/log/run
new file mode 100755
index 0000000..a8281ad
--- /dev/null
+++ b/examples/s6/httpsd-6/log/run
@@ -0,0 +1,5 @@
+#!/bin/execlineb -S1
+
+s6-setuidgid wwwlog
+exec -c
+s6-log -d3 t s1000000 n20 /var/log/httpsd-6
diff --git a/examples/s6/httpsd-6/notification-fd b/examples/s6/httpsd-6/notification-fd
new file mode 100644
index 0000000..00750ed
--- /dev/null
+++ b/examples/s6/httpsd-6/notification-fd
@@ -0,0 +1 @@
+3
diff --git a/examples/s6/httpsd-6/run b/examples/s6/httpsd-6/run
new file mode 100755
index 0000000..652a354
--- /dev/null
+++ b/examples/s6/httpsd-6/run
@@ -0,0 +1,11 @@
+#!/bin/execlineb -P
+
+fdmove -c 2 1
+backtick -E ip { pipeline { s6-dnsip6 example.com } head -n 1 }
+s6-envuidgid www
+export KEYFILE /etc/ssl/acme/private/example.com/key.pem
+export CERTFILE /etc/ssl/acme/example.com/cert.pem
+cd /home/www
+fdmove 1 3
+s6-tlsserver -v -6 -1 -U -c 512 -K 30000 -- $ip 443
+tipideed -v2 --
diff --git a/examples/tipidee.conf b/examples/tipidee.conf
index f75a9cc..705b88c 100644
--- a/examples/tipidee.conf
+++ b/examples/tipidee.conf
@@ -1,41 +1,79 @@
-### Global definitions
+### Global definitions.
 
-# After 1 minute without a new request, exit
-global read_timeout 60000
+# tipideed verbosity (overridden by the -v option).
+# 0 is quiet, 1 is normal, 2+ is verbose.
+# global verbosity 1
 
-# If the client fails to read a response for 1 minute, exit
-global write_timeout 60000
+# tipideed will exit if the client does not send a new request
+# after N milliseconds.
+# 0 means no timeout.
+# global read_timeout 0
 
-# If a CGI script takes more than 10s to run, kill it and respond 504 instead
-global cgi_timeout 10000
+# tipideed will drop the connection if sending a response has
+# not completed after N milliseconds.
+# 0 means no timeout.
+# global write_timeout 0
 
-# Serve .ini and .cfg files as plain text
-content-type text/plain .ini .cfg
+# tipideed will answer 504 ("Gateway Timeout") if a CGI program
+# (including NPH) does not complete in N milliseconds.
+# 0 means no timeout.
+# global cgi_timeout 0
 
+# tipideed will refuse to serve POST requests if the client-provided
+# data is larger than N bytes.
+# global max_request_body_length 8192
 
-### Definitions for the example.com virtual domain
-domain example.com
+# tipideed will answer 502 ("Bad Gateway") if a CGI script's answer
+# is larger than N bytes. (does not apply to NPH scripts)
+# global max_cgi_body_length 4194304
 
-# CGI scripts called nph-foobar are considered non-parsed-headers
-nph-prefix nph-
+# When the requested URL is a directory, tipideed will serve the first
+# existing file in this list. (Useful e.g. if you have an index.cgi program.)
+# global index_file index.html
 
-# CGI scripts live under /cgi-bin
-cgi /cgi-bin/
+# You can define your own Content-Type mappings by file extension.
+# The default mappings should work well for most servers.
+# content-type text/html .html .htm
 
-# Serve http://example.com/README as plain text
-file-type /README text/plain
+
+### Definitions for the example.com domain
+# domain example.com
+
+# If a CGI script under the current domain starts with this prefix,
+# it will be considered a NPH script (non-parsable headers).
+# nph-prefix nph-
+
+# If uncommented: every file under that directory will be considered
+# a CGI script.
+# cgi /cgi-bin/
+
+# You can also declare that individual files are CGI scripts.
+# cgi /index.cgi
+
+# If uncommented: every CGI script under that directory will be considered NPH.
+# nph /cgi-bin/nph/
+
+# You can also declare that individual scripts are NPH.
+# nph /cgi-bin/basic.cgi
+
+# You can override the default Content-Type for individual files,
+# no matter what extension they have.
+# file-type /README text/plain
 
 # Redirect http://example.com/rickroll to a fan favorite video.
 # Make it temporary to avoid revealing the trick in the client.
-redirect /rickroll 307 https://www.youtube.com/watch?v=dQw4w9WgXcQ
+# redirect /rickroll 307 https://www.youtube.com/watch?v=dQw4w9WgXcQ
 
 # Permanently redirect http://example.com/community/foobar... requests
 # to https://example.org/foobar...
-redirect /community/ 308 https://example.org
+# redirect /community/ 308 https://example.org
+
 
+### Definitions for the example.org domain
+# domain example.org
 
-### Definitions for the example.org virtual domain
-domain example.org
+# example.org has the same NPH prefix
+# nph-prefix nph-
 
-nph-prefix nph-
-cgi /cgi-bin/
+# example.org hosts CGI scripts in /cgi-bin as well
+# cgi /cgi-bin/
diff --git a/src/config/lexparse.c b/src/config/lexparse.c
index a7ed5b2..da9d7f5 100644
--- a/src/config/lexparse.c
+++ b/src/config/lexparse.c
@@ -99,7 +99,7 @@ static inline void parse_global (char const *s, size_t const *word, size_t n, md
     { .name = "verbosity", .key = "G:verbosity", .type = 0 },
     { .name = "write_timeout", .key = "G:write_timeout", .type = 0 }
   } ;
-  struct globalkey_s *gl ;
+  struct globalkey_s const *gl ;
   if (n < 2)
     strerr_dief8x(1, "too ", "few", " arguments to directive ", "global", " in file ", g.storage.s + md->filepos, " line ", md->linefmt) ;
   gl = bsearch(s + word[0], globalkeys, sizeof(globalkeys)/sizeof(struct globalkey_s), sizeof(struct globalkey_s), &globalkey_cmp) ;
@@ -194,7 +194,7 @@ static inline void parse_redirect (char const *s, size_t const *word, size_t n,
 
 static void parse_bitattr (char const *s, size_t const *word, size_t n, char const *domain, size_t domainlen, mdt const *md, unsigned int bit, int set)
 {
-  static char const *attr[3][2] = { { "noncgi", "cgi" }, { "nonnph", "nph", }, { "noauth", "basic-auth" } } ;
+  static char const *const attr[3][2] = { { "noncgi", "cgi" }, { "nonnph", "nph", }, { "noauth", "basic-auth" } } ;
   uint8_t mask = (uint8_t)0x01 << bit ;
   if (n != 1)
     strerr_dief8x(1, "too ", n > 1 ? "many" : "few", " arguments to directive ", attr[bit][set], " in file ", g.storage.s + md->filepos, " line ", md->linefmt) ;
diff --git a/src/config/tipidee-config-internal.h b/src/config/tipidee-config-internal.h
index e274f94..154c6ff 100644
--- a/src/config/tipidee-config-internal.h
+++ b/src/config/tipidee-config-internal.h
@@ -35,8 +35,6 @@ extern struct global_s g ;
 
 extern void confnode_start (confnode *, char const *, size_t, uint32_t) ;
 extern void confnode_add (confnode *, char const *, size_t) ;
-#define confnode_adds(node, s) confnode_add(node, (s), strlen(s))
-#define confnode_add0(node) confnode_add((node), "", 1)
 
 
  /* conftree */
diff --git a/src/config/tipidee-config-preprocess.c b/src/config/tipidee-config-preprocess.c
index 6ac4812..03b54f1 100644
--- a/src/config/tipidee-config-preprocess.c
+++ b/src/config/tipidee-config-preprocess.c
@@ -206,9 +206,11 @@ static void includefromhere (char const *file)
       switch (cmd)
       {
         case 2 :
+          if (namesa.s[d] & 2)
+            strerr_dief5x(3, "in ", namesa.s + d + 1, " line ", linefmt, ": extra !included: directive") ;
           if (!strcmp(sa.s + sastart, "unique")) namesa.s[d] |= 3 ;
           else if (!strcmp(sa.s + sastart, "multiple")) namesa.s[d] |= 2 ;
-          else strerr_dief6x(3, "in ", namesa.s + d + 1, " line ", linefmt, "invalid !included: argument: ", sa.s + sastart) ;
+          else strerr_dief6x(3, "in ", namesa.s + d + 1, " line ", linefmt, ": invalid !included: argument: ", sa.s + sastart) ;
           break ;
         case 1 :
         case 0 :
diff --git a/src/config/tipidee-config.c b/src/config/tipidee-config.c
index be13e39..36b1c03 100644
--- a/src/config/tipidee-config.c
+++ b/src/config/tipidee-config.c
@@ -52,11 +52,6 @@ static inline void conf_output (char const *ofile, unsigned int omode)
   memcpy(otmp + olen, ":XXXXXX", 8) ;
   fdw = mkstemp(otmp) ;
   if (fdw == -1) strerr_diefu3sys(111, "open ", otmp, " for writing") ;
-  if (coe(fdw) == -1)
-  {
-    unlink_void(otmp) ;
-    strerr_diefu2sys(111, "coe ", otmp) ;
-  }
   if (!cdbmake_start(&cm, fdw))
   {
     unlink_void(otmp) ;
@@ -77,7 +72,7 @@ static inline void conf_output (char const *ofile, unsigned int omode)
     unlink_void(otmp) ;
     strerr_diefu2sys(111, "fsync ", otmp) ;
   }
-  if (fchmod(fdw, omode & 0755) == -1)
+  if (fchmod(fdw, omode & 0777) == -1)
   {
     unlink_void(otmp) ;
     strerr_diefu2sys(111, "fchmod ", otmp) ;
diff --git a/src/tipideed/tipideed.c b/src/tipideed/tipideed.c
index 118f33a..f71be9f 100644
--- a/src/tipideed/tipideed.c
+++ b/src/tipideed/tipideed.c
@@ -30,6 +30,7 @@
 #define dieusage() strerr_dieusage(100, USAGE)
 #define dienomem() strerr_diefu1sys(111, "stralloc_catb")
 
+#define MAX_LOCALREDIRS 32
 #define ARGV_MAX 128
 
 struct global_s g = GLOBAL_ZERO ;
@@ -367,6 +368,7 @@ int main (int argc, char const *const *argv, char const *const *envp)
     tipidee_rql rql = TIPIDEE_RQL_ZERO ;
     tipidee_headers hdr ;
     int e ;
+    unsigned int localredirs = 0 ;
     char const *x ;
     size_t content_length ;
     tipidee_transfercoding tcoding = TIPIDEE_TRANSFERCODING_UNKNOWN ;
@@ -509,7 +511,9 @@ 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, hostlen + 1 + g.localportlen, uribuf, &hdr, bodysa.s, bodysa.len))
+        if (localredirs++ >= MAX_LOCALREDIRS)
+          die502x(&rql, 1, "too many local redirections - possible loop involving path ", rql.uri.path) ;
     }
   }
   log_and_exit(0) ;