On Tue, May 29, 2018 at 06:48:31PM +0200, Reyk Floeter wrote:
> Hi,
> 
> it's about time.
> 
>       server "default" {
>               listen on * port 80
>               location match "/de/(.*)" {
>                       request rewrite "/ch/%1"
>               }
>       }
> 
> You can also you the macros as in the "block return" external
> redirects.  So maybe something like:
> 
>       server "default" {
>               listen on * port 80
>               location match "/(.*)" {
>                       request rewrite "/$HTTP_HOST/%1"
>               }
>       }
> 

The syntax looks clear in my opinion.

Would it be a good idea in your opinion to have request path rewriting in
relayd also? For example to rewrite the request path for the (internal)
application?

For example for the url: "http://somesite.org/gopherproxy"; to rewrite the path
"/gopherproxy" to "/" for the application?

in Nginx my current rule is like:

        location /gopherproxy/ {
                rewrite    /gopherproxy/(.*) /$1 break;

                proxy_pass   http://127.0.0.1:6969/;
                proxy_set_header Host $host;
                proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
                proxy_pass_header Server;
        }

I have read the man page and relayd source-code, but have not found a way to
replace part of the pattern in the path (only a fixed string with "set").

> Tests? OK?
> 
> Please note that this diff intentionally breaks the "root strip"
> option because it changes the grammar to "request strip".  "root
> strip" was semantically wrong but we didn't have a better place to put
> it.  An current.html entry can be made for the required grammar change.
> 
> 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   29 May 2018 16:35:29 -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.95
> diff -u -p -u -p -r1.95 httpd.conf.5
> --- usr.sbin/httpd/httpd.conf.5       23 May 2018 19:02:50 -0000      1.95
> +++ usr.sbin/httpd/httpd.conf.5       29 May 2018 16:35:29 -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.
> @@ -458,12 +460,31 @@ instead of the log files.
>  Disable any previous
>  .Ic block
>  in a location.
> -.It Ic root Ar option
> -Configure the document root and options for the request path.
> +.It Ic request Ar option
> +Configure the options for the request path.
>  Valid options are:
>  .Bl -tag -width Ds
> -.It Ar directory
> -Set the document root of the server.
> +.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
> +path components from the beginning of the request path before looking
> +up the stripped-down path at the document root.
> +.El
> +.It Ic root Ar directory
> +Configure the document root of the server.
>  The
>  .Ar directory
>  is a pathname within the
> @@ -472,12 +493,6 @@ root directory of
>  .Nm httpd .
>  If not specified, it defaults to
>  .Pa /htdocs .
> -.It Ic strip Ar number
> -Strip
> -.Ar number
> -path components from the beginning of the request path before looking
> -up the stripped-down path at the document root.
> -.El
>  .It Ic tcp Ar option
>  Enable or disable the specified TCP/IP options; see
>  .Xr tcp 4
> @@ -715,6 +730,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    29 May 2018 16:35:30 -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.99
> diff -u -p -u -p -r1.99 parse.y
> --- usr.sbin/httpd/parse.y    23 May 2018 19:11:48 -0000      1.99
> +++ usr.sbin/httpd/parse.y    29 May 2018 16:35:31 -0000
> @@ -134,7 +134,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
> @@ -486,6 +486,7 @@ serveroptsl       : LISTEN ON STRING opttls po
>                               YYERROR;
>                       }
>               }
> +             | request
>               | root
>               | directory
>               | logformat
> @@ -804,7 +805,33 @@ rootflags        : STRING                {
>                       free($1);
>                       srv->srv_conf.flags |= SRVFLAG_ROOT;
>               }
> -             | STRIP NUMBER          {
> +             ;
> +
> +request              : REQUEST requestflags
> +             | REQUEST '{' optnl requestflags_l '}'
> +             ;
> +
> +requestflags_l       : requestflags optcommanl requestflags_l
> +             | requestflags optnl
> +             ;
> +
> +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;
> @@ -1261,6 +1288,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.119
> diff -u -p -u -p -r1.119 server_http.c
> --- usr.sbin/httpd/server_http.c      6 Apr 2018 13:02:07 -0000       1.119
> +++ usr.sbin/httpd/server_http.c      29 May 2018 16:35:31 -0000
> @@ -1180,10 +1180,13 @@ server_response(struct httpd *httpd, str
>       char                    *hostval;
>       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)
> @@ -1286,6 +1289,28 @@ 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) {
> +             if (server_expand_http(clt, srv_conf->path,
> +                 path, sizeof(path)) == NULL)
> +                     goto fail;
> +
> +             /* Canonicalize the updated request path */
> +             if (canonicalize_path(path,
> +                 path, sizeof(path)) == NULL)
> +                     goto fail;
> +
> +             log_debug("%s: rewrote %s -> %s", __func__,
> +                 desc->http_path, path);
> +
> +             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,
> 

-- 
Kind regards,
Hiltjo

Reply via email to