Header_up -field in reverse_proxy will affect placeholders {http.request.header.field}?

1. Caddy version (caddy version):

v2.4.6 h1:HGkGICFGvyrodcqOOclHKfvJC0qTU7vny/7FhYp9hNw=

2. How I run Caddy:

:12345 {
    respond "hello world! {http.request.header.Origin}"
}

:23456 {
    @origin {
        header Origin *
    }
    @preflight {
        header Origin *
        method OPTIONS
    }
    header @origin {
        Access-Control-Allow-Origin "{http.request.header.Origin}"
        Access-Control-Allow-Credentials true
        Access-Control-Expose-Headers "Content-Length,Content-Range"
        defer
    }
    header @preflight {
        Access-Control-Allow-Methods "GET,POST,PUT,DELETE,HEAD,OPTIONS"
        Access-Control-Allow-Headers "{http.request.header.Access-Control-Request-Headers}"
        Access-Control-Max-Age 86400
    }
    reverse_proxy http://localhost:12345 {
        header_up -Origin
        header_down -Server
    }
}

a. System environment:

Docker 20.10.10

b. Command:

caddy run;

c. Service/unit/compose file:

docker run --name caddy --net=host -e TZ=Asia/Shanghai -e GO111MODULE=on -e GOPROXY=https://goproxy.cn,direct --restart=always -v /data/www:/data/www:ro -v /opt/caddy/config:/etc/caddy:ro -v /opt/caddy/log:/log -w /etc/caddy -d caddy:builder-alpine sh -c "if [ ! -x /usr/bin/caddy ]; then xcaddy build --output /usr/bin/caddy --with github.com/caddyserver/format-encoder; fi; caddy run"

d. My complete Caddyfile or JSON config:

:12345 {
    respond "hello world! {http.request.header.Origin}"
}

:23456 {
    @origin {
        header Origin *
    }
    @preflight {
        header Origin *
        method OPTIONS
    }
    header @origin {
        Access-Control-Allow-Origin "{http.request.header.Origin}"
        Access-Control-Allow-Credentials true
        Access-Control-Expose-Headers "Content-Length,Content-Range"
        defer
    }
    header @preflight {
        Access-Control-Allow-Methods "GET,POST,PUT,DELETE,HEAD,OPTIONS"
        Access-Control-Allow-Headers "{http.request.header.Access-Control-Request-Headers}"
        Access-Control-Max-Age 86400
    }
    reverse_proxy http://localhost:12345 {
        header_up -Origin
        header_down -Server
    }
}

3. The problem I’m having:

I want to use caddy to support CORS and disable the CORS logic of the upstream.

curl -v http://localhost:23456 -H "Origin: test"
*   Trying ::1...
* TCP_NODELAY set
* Expire in 150000 ms for 3 (transfer 0x55695f06af50)
* Expire in 200 ms for 4 (transfer 0x55695f06af50)
* Connected to localhost (::1) port 23456 (#0)
> GET / HTTP/1.1
> Host: localhost:23456
> User-Agent: curl/7.64.0
> Accept: */*
> Origin: test
> 
< HTTP/1.1 200 OK
< Access-Control-Allow-Credentials: true
< Access-Control-Allow-Origin: 
< Access-Control-Expose-Headers: Content-Length,Content-Range
< Content-Length: 13
< Date: Sun, 05 Dec 2021 04:56:33 GMT
< Server: Caddy
< Content-Type: text/plain; charset=utf-8
< 
* Connection #0 to host localhost left intact
hello world! 

4. Error messages and/or full log output:

5. What I already tried:

I couldn’t find the relevant information in the forum, and then pulled out the simplest Caddyfile, which contains no other information and can be reproduced 100%.

6. Links to relevant resources:

Caddyfile can be simpler.

:12345 {
    respond "hello world! {http.request.header.Origin}"
}

:23456 {
    @origin {
        header Origin *
    }
    header @origin {
        Access-Control-Allow-Origin "{http.request.header.Origin}"
        Access-Control-Allow-Credentials true
        Access-Control-Expose-Headers "Content-Length,Content-Range"
        defer
    }
    reverse_proxy http://localhost:12345 {
        header_up -Origin
        header_down -Server
    }
}

Caddy’s reverse_proxy module doesn’t make a full copy of the request, it instead just mutates the existing request. This means that certain kinds of header modifications don’t get properly reset afterwards (they probably should, might be a bug).

But there is a workaround for now. You can use the header_regexp matcher to pull the values out and store them in the replacer so that you can use them again later. It would look something like this:

2 Likes

I wonder if copying the request, like the std lib’s proxy does, is a reasonable tradeoff. (It would perform less well, however, adding plenty of allocations.)

save the header modified by header_up into a temporary map?

Thank you, this can really help me.

This topic was automatically closed after 30 days. New replies are no longer allowed.