Awesome, thanks!

I reviewed and tested and all looks fine.
I don't want to bother you but I see two improvings:

1. While ETag minimizes load on each load will be sent a new request. To
avoid such requests at all for assets we can add a header Cache-Control:
public,max-age=31536000,immutable
But users may want some other values so it would be great to have a general
ability to add a custom header.
This can be implemented just as a regular httpd.conf file in a folder with
the value of a custom header.
The same can be used for Content Security Policy (CSP) headers and many
other things.
Some users are looking for the functionality
https://serverfault.com/questions/918602/how-to-set-header-with-busybox-httpd
Will you accept a patch for custom headers?

2. BB httpd has a built-in IP ACL i.e. allow/deny by IP. This work can be
done by a firewall or iptables. We can also make it configurable:

Subject: [PATCH] httpd: Make Deny/Allow by IP config support optional

Signed-off-by: Sergey Ponomarev <stok...@gmail.com>
---
 networking/httpd.c | 27 ++++++++++++++++++++++++++-
 1 file changed, 26 insertions(+), 1 deletion(-)

diff --git a/networking/httpd.c b/networking/httpd.c
index 0297cf9ec..7ddf6caaa 100644
--- a/networking/httpd.c
+++ b/networking/httpd.c
@@ -245,6 +245,13 @@
 //config: help
 //config: RFC2616 says that server MUST add Date header to response.
 //config: But it is almost useless and can be omitted.
+//config:
+//config:config FEATURE_HTTPD_ACL
+//config: bool "ACL IP"
+//config: default y
+//config: depends on HTTPD
+//config: help
+//config: Deny/Allow by IP config support

 //applet:IF_HTTPD(APPLET(httpd, BB_DIR_USR_SBIN, BB_SUID_DROP))

@@ -314,6 +321,7 @@ typedef struct Htaccess {
   char before_colon[1];  /* really bigger, must be last */
 } Htaccess;

+#if ENABLE_FEATURE_HTTPD_ACL_IP
 /* Must have "next" as a first member */
 typedef struct Htaccess_IP {
   struct Htaccess_IP *next;
@@ -321,6 +329,7 @@ typedef struct Htaccess_IP {
   unsigned mask;
   int allow_deny;
 } Htaccess_IP;
+#endif

 /* Must have "next" as a first member */
 typedef struct Htaccess_Proxy {
@@ -449,7 +458,9 @@ struct globals {

   const char *found_mime_type;
   const char *found_moved_temporarily;
+#if ENABLE_FEATURE_HTTPD_ACL_IP
   Htaccess_IP *ip_a_d;    /* config allow/deny lines */
+#endif

   IF_FEATURE_HTTPD_BASIC_AUTH(const char *g_realm;)
   IF_FEATURE_HTTPD_BASIC_AUTH(char *remoteuser;)
@@ -499,7 +510,9 @@ struct globals {
 #define found_mime_type   (G.found_mime_type  )
 #define found_moved_temporarily (G.found_moved_temporarily)
 #define last_mod          (G.last_mod         )
-#define ip_a_d            (G.ip_a_d           )
+#if ENABLE_FEATURE_HTTPD_ACL_IP
+# define ip_a_d            (G.ip_a_d           )
+#endif
 #define g_realm           (G.g_realm          )
 #define remoteuser        (G.remoteuser       )
 #define file_size         (G.file_size        )
@@ -560,6 +573,7 @@ static ALWAYS_INLINE void
free_Htaccess_list(Htaccess **pptr)
   free_llist((has_next_ptr**)pptr);
 }

+#if ENABLE_FEATURE_HTTPD_ACL_IP
 static ALWAYS_INLINE void free_Htaccess_IP_list(Htaccess_IP **pptr)
 {
   free_llist((has_next_ptr**)pptr);
@@ -649,6 +663,7 @@ static int scan_ip_mask(const char *str, unsigned
*ipp, unsigned *maskp)
   *maskp = (uint32_t)(~mask);
   return 0;
 }
+#endif

 /*
  * Parse configuration file into in-memory linked list.
@@ -677,8 +692,10 @@ static void parse_conf(const char *path, int flag)
   const char *filename;
   char buf[160];

+#if ENABLE_FEATURE_HTTPD_ACL_IP
   /* discard old rules */
   free_Htaccess_IP_list(&ip_a_d);
+#endif
   flg_deny_all = 0;
   /* retain previous auth and mime config only for subdir parse */
   if (flag != SUBDIR_PARSE) {
@@ -783,6 +800,7 @@ static void parse_conf(const char *path, int flag)
         continue;
      }

+#if ENABLE_FEATURE_HTTPD_ACL_IP
      if (ch == 'A' || ch == 'D') {
         Htaccess_IP *pip;

@@ -819,6 +837,7 @@ static void parse_conf(const char *path, int flag)
         }
         continue;
      }
+#endif

 #if ENABLE_FEATURE_HTTPD_ERROR_PAGES
      if (flag == FIRST_PARSE && ch == 'E') {
@@ -1920,6 +1939,7 @@ static NOINLINE void send_file_and_exit(const
char *url, int what)
   log_and_exit();
 }

+#if ENABLE_FEATURE_HTTPD_ACL_IP
 static void if_ip_denied_send_HTTP_FORBIDDEN_and_exit(unsigned remote_ip)
 {
   Htaccess_IP *cur;
@@ -1949,6 +1969,7 @@ static void
if_ip_denied_send_HTTP_FORBIDDEN_and_exit(unsigned remote_ip)
   if (flg_deny_all) /* depends on whether we saw "D:*" */
      send_headers_and_exit(HTTP_FORBIDDEN);
 }
+#endif

 #if ENABLE_FEATURE_HTTPD_BASIC_AUTH

@@ -2228,7 +2249,9 @@ static void handle_incoming_and_exit(const
len_and_sockaddr *fromAddr)
      if (verbose > 2)
         bb_simple_error_msg("connected");
   }
+#if ENABLE_FEATURE_HTTPD_ACL_IP
   if_ip_denied_send_HTTP_FORBIDDEN_and_exit(remote_ip);
+#endif

   /* Install timeout handler. get_line() needs it. */
   signal(SIGALRM, send_REQUEST_TIMEOUT_and_exit);
@@ -2378,7 +2401,9 @@ static void handle_incoming_and_exit(const
len_and_sockaddr *fromAddr)
      if (is_directory(urlcopy + 1, /*followlinks:*/ 1)) {
         /* may have subdir config */
         parse_conf(urlcopy + 1, SUBDIR_PARSE);
+#if ENABLE_FEATURE_HTTPD_ACL_IP
         if_ip_denied_send_HTTP_FORBIDDEN_and_exit(remote_ip);
+#endif
      }
      *tptr = '/';
   }
-- 
2.25.1





On Sun, 16 Aug 2020 at 00:57, Denys Vlasenko <vda.li...@googlemail.com>
wrote:

> I applied patch 4 as well with some edits.
> Please test current git.
> Thank you.
>
> On Sat, Aug 15, 2020 at 11:05 PM Denys Vlasenko
> <vda.li...@googlemail.com> wrote:
> >
> > On Sun, Aug 9, 2020 at 12:24 AM Sergey Ponomarev <stok...@gmail.com>
> wrote:
> > >
> > > If server respond with ETag then next time client (browser) resend it
> via If-None-Match header.
> > > Then httpd will check if file wasn't modified and if not return 304
> Not Modified status code.
> > > The ETag value is constructed from file's last modification date in
> unix epoch and it's size:
> > > "hex(last_mod)-hex(file_size)" e.g. "5e132e20-417" (with quotes).
> > > That means that it's not completely reliable as hash functions but
> fair enough.
> > > The same form of ETag is used by Nginx so load balancing of static
> content is safe.
> > >
> > > Signed-off-by: Sergey Ponomarev <stok...@gmail.com>
> > > ---
> > >  networking/httpd.c | 73 ++++++++++++++++++++++++++++++++++++++++++++--
> > >  1 file changed, 70 insertions(+), 3 deletions(-)
> > >
> > > diff --git a/networking/httpd.c b/networking/httpd.c
> > > index 1cea33ddd..cc3f757aa 100644
> > > --- a/networking/httpd.c
> > > +++ b/networking/httpd.c
> > > @@ -215,6 +215,17 @@
> > >  //config:      Makes httpd send files using GZIP content encoding if
> the
> > >  //config:      client supports it and a pre-compressed <file>.gz
> exists.
> > >  //config:
> > > +//config:config FEATURE_HTTPD_ETAG
> > > +//config:      bool "Support caching via ETag header"
> > > +//config:      default y
> > > +//config:      depends on HTTPD
> > > +//config:      help
> > > +//config:      If server respond with ETag then next time client
> (browser) resend it via If-None-Match header.
> > > +//config:      Then httpd will check if file wasn't modified and if
> not return 304 Not Modified status code.
> > > +//config:      The ETag value is constructed from file's last
> modification date in unix epoch and it's size:
> > > +//config:      "hex(last_mod)-hex(file_size)" e.g. "5e132e20-417"
> (with quotes).
> > > +//config:      That means that it's not completely reliable as hash
> functions but fair enough.
> >
> > $ make
> >   GEN     networking/Config.in
> > scripts/kconfig/conf -s Config.in
> > networking/Config.in:294 error: Overlong line
> > networking/Config.in:295 error: Overlong line
> > networking/Config.in:296 error: Overlong line
> > networking/Config.in:298 error: Overlong line
> > networking/Config.in:306 error: Overlong line
> > networking/Config.in:307 error: Overlong line
> > #
> > # using defaults found in .config
> >
> >
> > > +//config:
> > >  //config:config FEATURE_HTTPD_LAST_MODIFIED
> > >  //config:      bool "Add Last-Modified header to response"
> > >  //config:      default y
> > > @@ -266,6 +277,7 @@
> > >
> > >  #include "libbb.h"
> > >  #include "common_bufsiz.h"
> > > +#include <inttypes.h>
> >
> > libbb.h includes inttypes.h
> >
> > > +/*
> > > + * ETag is "hex(last_mod)-hex(file_size)" e.g. "5e132e20-417"
> > > + */
> > > +static char *make_etag(void)
> > > +{
> > > +       return xasprintf("\"%" PRIx64 "-%" PRIx64 "\"", last_mod,
> file_size);
> > > +}
> > > +
> >
> > networking/httpd.c: In function 'make_etag':
> > networking/httpd.c:1082:19: error: format '%llx' expects argument of
> > type 'long long unsigned int', but argument 2 has type 'time_t {aka
> > long int}' [-Werror=format=]
> >   return xasprintf("\"%" PRIx64 "-%" PRIx64 "\"", last_mod, file_size);
> >                    ^~~~~
>


-- 
Sergey Ponomarev <https://linkedin.com/in/stokito>, skype:stokito
_______________________________________________
busybox mailing list
busybox@busybox.net
http://lists.busybox.net/mailman/listinfo/busybox

Reply via email to