Search code examples
regexurl-rewritinghaproxy

HAProxy 1.6+: rewrite host based on path


I'm trying to redirect all requested of type:

static.domain.com/site1/resource.jpg
static.domain.com/site1/resource2.js
static.domain.com/site2/resource3.gif
static.domain.com/site2/someDir/resource4.txt

to

site1.domain.com/resource.jpg
site1.domain.com/resource2.js
site2.domain.com/resource3.gif
site2.domain.com/someDir/resource4.txt

Basically, if the host is static.domain.com:

  1. New subdomain is based on the the first part of the original path, with same TLD
  2. New path is the original path not including the first part

I am pretty sure regexps can solve this, just not sure how to modify one header based on another..


Solution

  • At first I thought this might work:

    # Detect hosts of the format static.*
    acl host_static hdr_beg(host) -i static.
    
    # Style using reqirep
    # -------------
    # Replace "static.domain.com" with "someFolder.domain.com" if the host is static.* and the path has at least two / symbols
    # This causes: static.domain.com ===> whatever3.domain.com
    #reqirep ^([^\ :]*\ /)([^/]+)(/.*\n)(^(?:[a-zA-Z0-9()\-=\*\.\?;,+\/&_]+:\ .+\n)+)*Host:\ static\.([^/]+?)$ \1\2\3\4Host:\ \2.\5 if host_static
    #
    # Replace "/someFolder/" with "/" at the beginning of any request path, if the host is static.*
    # This causes: /whatever3/another/long/path ===> /another/long/path
    #reqirep ^([^\ :]*)\ /[^/]+/(.*)     \1\ /\2 if host_static
    #---------------
    

    but it doesn't work as expected. The regexp works properly in controlled tests, but not in haproxy itself. Probably an issue of directive processing and execution order. (perhaps the modification of the request path screws the first regexp?)

    I then tried this:

    # Style using set-var, set-path etc
    #---------------
    #http-request set-var(req.first_path_part)   path,field(2,/) if host_static
    #http-request set-var(req.last_host_part)    hdr(host),regsub(^static\.,) if host_static
    #http-request replace-header     Host        .* %[var(req.first_path_part)].%[var(req.last_host_part)] if host_static
    #http-request set-path                       %[path,regsub(^/.*?/,/)] if host_static
    #---------------
    

    Once again, it almost works, but for some reason the host doesn't get replaced properly.

    Since this was only used by the QA env, and the behaviour is different from Production anyways (static.*, in my case, would point to a CDN), I decided this is a sufficient solution for now:

    # New style, using set-var and redirection.
    #---------------
    http-request set-var(req.first_path_part)   path,field(2,/) if host_static
    http-request set-var(req.last_host_part)    hdr(host),regsub(^static\.,) if host_static
    http-request redirect location https://%[var(req.first_path_part)].%[var(req.last_host_part)]%[path,regsub(^/.*?/,/)] code 302 if host_static
    #---------------