Hi Reyk,

I have tested your patch against -current httpd and it works well on my setup.

Mischa


On 20 Jun at 16:41, Reyk Floeter <[email protected]> wrote:
> anyone?
> 
> On Wed, Jun 13, 2018 at 05:20:55PM +0200, Reyk Floeter wrote:
> > On Wed, May 30, 2018 at 12:36:05AM +0200, Reyk Floeter wrote:
> > > as mentioned in the big diff before, this implements rewrites.  This
> > > diff applies on top of the previous ones.
> > > 
> > >     Implement the "request rewrite" option for internal rewrites.
> > >     
> > >     For example:
> > >     
> > >             location match "/page/(%d+)/.*" {
> > >                     request rewrite 
> > > "/static/index.php?id=%1&$QUERY_STRING"
> > >             }
> > > 
> > > Please note that httpd uses patterns(7) and not regex.
> > > 
> > 
> > Same, diff, re-applied on top of the previous commits.
> > 
> > OK?
> > 
> > Reyk
> > 
> > Index: usr.sbin/httpd/config.c
> > ===================================================================
> > RCS file: /cvs/src/usr.sbin/httpd/config.c,v
> > retrieving revision 1.54
> > diff -u -p -u -p -r1.54 config.c
> > --- usr.sbin/httpd/config.c 19 May 2018 13:56:56 -0000      1.54
> > +++ usr.sbin/httpd/config.c 13 Jun 2018 15:18:24 -0000
> > @@ -476,6 +476,13 @@ config_getserver_config(struct httpd *en
> >                         &parent->default_type, sizeof(struct media_type));
> >             }
> >  
> > +           f = SRVFLAG_PATH_REWRITE|SRVFLAG_NO_PATH_REWRITE;
> > +           if ((srv_conf->flags & f) == 0) {
> > +                   srv_conf->flags |= parent->flags & f;
> > +                   (void)strlcpy(srv_conf->path, parent->path,
> > +                       sizeof(srv_conf->path));
> > +           }
> > +
> >             f = SRVFLAG_SERVER_HSTS;
> >             srv_conf->flags |= parent->flags & f;
> >             srv_conf->hsts_max_age = parent->hsts_max_age;
> > Index: usr.sbin/httpd/httpd.conf.5
> > ===================================================================
> > RCS file: /cvs/src/usr.sbin/httpd/httpd.conf.5,v
> > retrieving revision 1.97
> > diff -u -p -u -p -r1.97 httpd.conf.5
> > --- usr.sbin/httpd/httpd.conf.5     13 Jun 2018 15:08:24 -0000      1.97
> > +++ usr.sbin/httpd/httpd.conf.5     13 Jun 2018 15:18:25 -0000
> > @@ -198,6 +198,8 @@ argument can be used with return codes i
> >  .Sq Location:
> >  header for redirection to a specified URI.
> >  .Pp
> > +It is possible to rewrite the request to redirect it to a different
> > +external location.
> >  The
> >  .Ar uri
> >  may contain predefined macros that will be expanded at runtime:
> > @@ -396,10 +398,10 @@ the
> >  using pattern matching instead of shell globbing rules,
> >  see
> >  .Xr patterns 7 .
> > -The pattern may contain captures that can be used in the
> > -.Ar uri
> > -of an enclosed
> > +The pattern may contain captures that can be used in an enclosed
> >  .Ic block return
> > +or
> > +.Ic request rewrite
> >  option.
> >  .It Oo Ic no Oc Ic log Op Ar option
> >  Set the specified logging options.
> > @@ -462,6 +464,19 @@ in a location.
> >  Configure the options for the request path.
> >  Valid options are:
> >  .Bl -tag -width Ds
> > +.It Oo Ic no Oc Ic rewrite Ar path
> > +Enable or disable rewriting of the request.
> > +Unlike the redirection with
> > +.Ic block return ,
> > +this will change the request path internally before
> > +.Nm httpd
> > +makes a final decision about the matching location.
> > +The
> > +.Ar path
> > +argument may contain predefined macros that will be expanded at runtime.
> > +See the
> > +.Ic block return
> > +option for the list of supported macros.
> >  .It Ic strip Ar number
> >  Strip
> >  .Ar number
> > @@ -721,6 +736,17 @@ server "example.com" {
> >  
> >  server "www.example.com" {
> >     listen on 10.0.0.1 port 80
> > +}
> > +.Ed
> > +The request can also be rewritten with the
> > +.Ic request rewrite
> > +directive:
> > +.Bd -literal -offset indent
> > +server "example.com" {
> > +   listen on * port 80
> > +   location match "/old/(.*)" {
> > +           request rewrite "/new/%1"
> > +   }
> >  }
> >  .Ed
> >  .Sh SEE ALSO
> > Index: usr.sbin/httpd/httpd.h
> > ===================================================================
> > RCS file: /cvs/src/usr.sbin/httpd/httpd.h,v
> > retrieving revision 1.137
> > diff -u -p -u -p -r1.137 httpd.h
> > --- usr.sbin/httpd/httpd.h  19 May 2018 13:56:56 -0000      1.137
> > +++ usr.sbin/httpd/httpd.h  13 Jun 2018 15:18:25 -0000
> > @@ -398,13 +398,15 @@ SPLAY_HEAD(client_tree, client);
> >  #define SRVFLAG_SERVER_MATCH       0x00200000
> >  #define SRVFLAG_SERVER_HSTS        0x00400000
> >  #define SRVFLAG_DEFAULT_TYPE       0x00800000
> > +#define SRVFLAG_PATH_REWRITE       0x01000000
> > +#define SRVFLAG_NO_PATH_REWRITE    0x02000000
> >  
> >  #define SRVFLAG_BITS                                                       
> > \
> >     "\10\01INDEX\02NO_INDEX\03AUTO_INDEX\04NO_AUTO_INDEX"           \
> >     "\05ROOT\06LOCATION\07FCGI\10NO_FCGI\11LOG\12NO_LOG\13SOCKET"   \
> >     "\14SYSLOG\15NO_SYSLOG\16TLS\17ACCESS_LOG\20ERROR_LOG"          \
> >     "\21AUTH\22NO_AUTH\23BLOCK\24NO_BLOCK\25LOCATION_MATCH"         \
> > -   "\26SERVER_MATCH\27SERVER_HSTS\30DEFAULT_TYPE"
> > +   "\26SERVER_MATCH\27SERVER_HSTS\30DEFAULT_TYPE\31PATH\32NO_PATH"
> >  
> >  #define TCPFLAG_NODELAY            0x01
> >  #define TCPFLAG_NNODELAY   0x02
> > @@ -470,8 +472,9 @@ struct server_config {
> >     uint32_t                 parent_id;
> >     char                     name[HOST_NAME_MAX+1];
> >     char                     location[HTTPD_LOCATION_MAX];
> > -   char                     index[PATH_MAX];
> >     char                     root[PATH_MAX];
> > +   char                     path[PATH_MAX];
> > +   char                     index[PATH_MAX];
> >     char                     socket[PATH_MAX];
> >     char                     accesslog[PATH_MAX];
> >     char                     errorlog[PATH_MAX];
> > Index: usr.sbin/httpd/parse.y
> > ===================================================================
> > RCS file: /cvs/src/usr.sbin/httpd/parse.y,v
> > retrieving revision 1.102
> > diff -u -p -u -p -r1.102 parse.y
> > --- usr.sbin/httpd/parse.y  13 Jun 2018 15:08:24 -0000      1.102
> > +++ usr.sbin/httpd/parse.y  13 Jun 2018 15:18:25 -0000
> > @@ -139,7 +139,7 @@ typedef struct {
> >  %token     LISTEN LOCATION LOG LOGDIR MATCH MAXIMUM NO NODELAY OCSP ON 
> > PORT PREFORK
> >  %token     PROTOCOLS REQUESTS ROOT SACK SERVER SOCKET STRIP STYLE SYSLOG 
> > TCP TICKET
> >  %token     TIMEOUT TLS TYPE TYPES HSTS MAXAGE SUBDOMAINS DEFAULT PRELOAD 
> > REQUEST
> > -%token     ERROR INCLUDE AUTHENTICATE WITH BLOCK DROP RETURN PASS
> > +%token     ERROR INCLUDE AUTHENTICATE WITH BLOCK DROP RETURN PASS REWRITE
> >  %token     CA CLIENT CRL OPTIONAL
> >  %token     <v.string>      STRING
> >  %token  <v.number> NUMBER
> > @@ -820,7 +820,23 @@ requestflags_l : requestflags optcommanl
> >             | requestflags optnl
> >             ;
> >  
> > -requestflags       : STRIP NUMBER                  {
> > +requestflags       : REWRITE STRING                {
> > +                   if (strlcpy(srv->srv_conf.path, $2,
> > +                       sizeof(srv->srv_conf.path)) >=
> > +                       sizeof(srv->srv_conf.path)) {
> > +                           yyerror("request path too long");
> > +                           free($2);
> > +                           YYERROR;
> > +                   }
> > +                   free($2);
> > +                   srv->srv_conf.flags |= SRVFLAG_PATH_REWRITE;
> > +                   srv->srv_conf.flags &= ~SRVFLAG_NO_PATH_REWRITE;
> > +           }
> > +           | NO REWRITE                    {
> > +                   srv->srv_conf.flags |= SRVFLAG_NO_PATH_REWRITE;
> > +                   srv->srv_conf.flags &= ~SRVFLAG_PATH_REWRITE;
> > +           }
> > +           | STRIP NUMBER                  {
> >                     if ($2 < 0 || $2 > INT_MAX) {
> >                             yyerror("invalid strip number");
> >                             YYERROR;
> > @@ -1277,6 +1293,7 @@ lookup(char *s)
> >             { "request",            REQUEST },
> >             { "requests",           REQUESTS },
> >             { "return",             RETURN },
> > +           { "rewrite",            REWRITE },
> >             { "root",               ROOT },
> >             { "sack",               SACK },
> >             { "server",             SERVER },
> > Index: usr.sbin/httpd/server_http.c
> > ===================================================================
> > RCS file: /cvs/src/usr.sbin/httpd/server_http.c,v
> > retrieving revision 1.120
> > diff -u -p -u -p -r1.120 server_http.c
> > --- usr.sbin/httpd/server_http.c    11 Jun 2018 12:12:51 -0000      1.120
> > +++ usr.sbin/httpd/server_http.c    13 Jun 2018 15:18:25 -0000
> > @@ -1,7 +1,7 @@
> >  /* $OpenBSD: server_http.c,v 1.120 2018/06/11 12:12:51 reyk Exp $  */
> >  
> >  /*
> > - * Copyright (c) 2006 - 2017 Reyk Floeter <[email protected]>
> > + * Copyright (c) 2006 - 2018 Reyk Floeter <[email protected]>
> >   *
> >   * Permission to use, copy, modify, and distribute this software for any
> >   * purpose with or without fee is hereby granted, provided that the above
> > @@ -1170,13 +1170,16 @@ server_response(struct httpd *httpd, str
> >     struct kv               *kv, key, *host;
> >     struct str_find          sm;
> >     int                      portval = -1, ret;
> > -   char                    *hostval;
> > +   char                    *hostval, *query;
> >     const char              *errstr = NULL;
> >  
> > -   /* Canonicalize the request path */
> > +   /* Decode the URL */
> >     if (desc->http_path == NULL ||
> > -       url_decode(desc->http_path) == NULL ||
> > -       canonicalize_path(desc->http_path, path, sizeof(path)) == NULL)
> > +       url_decode(desc->http_path) == NULL)
> > +           goto fail;
> > +
> > +   /* Canonicalize the request path */
> > +   if (canonicalize_path(desc->http_path, path, sizeof(path)) == NULL)
> >             goto fail;
> >     free(desc->http_path);
> >     if ((desc->http_path = strdup(path)) == NULL)
> > @@ -1279,6 +1282,42 @@ server_response(struct httpd *httpd, str
> >  
> >     /* Now search for the location */
> >     srv_conf = server_getlocation(clt, desc->http_path);
> > +
> > +   /* Optional rewrite */
> > +   if (srv_conf->flags & SRVFLAG_PATH_REWRITE) {
> > +           /* Expand macros */
> > +           if (server_expand_http(clt, srv_conf->path,
> > +               path, sizeof(path)) == NULL)
> > +                   goto fail;
> > +
> > +           /*
> > +            * Reset and update the query.  The updated query must already
> > +            * be URL encoded - either specified by the user or by using the
> > +            * original $QUERY_STRING.
> > +            */
> > +           free(desc->http_query);
> > +           desc->http_query = NULL;
> > +           if ((query = strchr(path, '?')) != NULL) {
> > +                   *query++ = '\0';
> > +                   if ((desc->http_query = strdup(query)) == NULL)
> > +                           goto fail;
> > +           }
> > +
> > +           /* Canonicalize the updated request path */
> > +           if (canonicalize_path(path,
> > +               path, sizeof(path)) == NULL)
> > +                   goto fail;
> > +
> > +           log_debug("%s: rewrote %s -> %s?%s", __func__,
> > +               desc->http_path, path, desc->http_query);
> > +
> > +           free(desc->http_path);
> > +           if ((desc->http_path = strdup(path)) == NULL)
> > +                   goto fail;
> > +
> > +           /* Now search for the updated location */
> > +           srv_conf = server_getlocation(clt, desc->http_path);
> > +   }
> >  
> >     if (srv_conf->flags & SRVFLAG_BLOCK) {
> >             server_abort_http(clt, srv_conf->return_code,
> 
> -- 
> 

Reply via email to