apache / apisix-go-plugin-runner

Go Plugin Runner for APISIX
https://apisix.apache.org/
Apache License 2.0
167 stars 69 forks source link

bug: pkgHTTP.Request RespHeader() Add override previous value #74

Open goxiaoy opened 2 years ago

goxiaoy commented 2 years ago

Issue description

w http.ResponseWriter, r pkgHTTP.Request
r.RespHeader().Add("Set-Cookie","a=a; Expires=Wed, 21 Oct 2023 07:28:00 GMT; Secure; HttpOnly")
r.RespHeader().Add("Set-Cookie","b=b; Expires=Wed, 21 Oct 2023 07:28:00 GMT; Secure; HttpOnly")

Cookie a is missing in the response header

Environment

Minimal test code / Steps to reproduce the issue

  1. Start APISIX on docker
  2. Set Plugin filter codes
    
    Filter(conf interface{}, w http.ResponseWriter, r pkgHTTP.Request)
    {
    r.RespHeader().Add("Set-Cookie","a=a; Expires=Wed, 21 Oct 2023 07:28:00 GMT; Secure; HttpOnly")
    r.RespHeader().Add("Set-Cookie","b=b; Expires=Wed, 21 Oct 2023 07:28:00 GMT; Secure; HttpOnly")
    return
    }

4. Cookie `a` is missing in the response header

### What's the actual result? (including assertion message & call stack if applicable)

Cookie `b` can be found, Cookie `a` is missing

### What's the expected result?
Both cookie `a` and `b` could be found
goxiaoy commented 2 years ago

https://github.com/apache/apisix/blob/f624fb0a4d33e5aa674ec659e9d778da2ef9860f/apisix/plugins/ext-plugin/init.lua#L626-L635

            local len = rewrite:RespHeadersLength()
            if len > 0 then
                for i = 1, len do
                    local entry = rewrite:RespHeaders(i)
                    local name = entry:Name()
                    if exclude_resp_header[str_lower(name)] == nil then
                        core.response.set_header(name, entry:Value())
                    end
                end
            end

Codes here should take multiple header with same name into account

@rampagecong @shuaijinchao

rampagecong commented 2 years ago

Very good idea. I'll give it a try.

shuaijinchao commented 2 years ago

Very good idea. I'll give it a try.

Currently in Runner, headers are stored using map, which does not support repeated header settings, which may require us to extend the header key. If you have better ideas, you can always reply here.

cc @Goxiaoy

goxiaoy commented 2 years ago

Origin servers SHOULD NOT fold multiple Set-Cookie header fields into a single header field. The usual mechanism for folding HTTP headers fields (i.e., as defined in [RFC2616]) might change the semantics of the Set-Cookie header field because the %x2C (",") character is used by Set-Cookie in a way that conflicts with such folding.

So it is a common use case for set multiple header with same name like Set-Cookie

            local len = rewrite:RespHeadersLength()
            if len > 0 then
                for i = 1, len do
                    local entry = rewrite:RespHeaders(i)
                    local name = entry:Name()
                    if exclude_resp_header[str_lower(name)] == nil then
-                        core.response.set_header(name, entry:Value())
+                        core.response.add_header(name, entry:Value())
                    end
                end
            end

Might fix this bug Should I open a new issue in APISIX?

rampagecong commented 2 years ago

@shuaijinchao I've tested the code above and it worked. But I'm not sure if core.response.add_header will break anything else. Could you please take a look?

shuaijinchao commented 2 years ago

@shuaijinchao I've tested the code above and it worked. But I'm not sure if core.response.add_header will break anything else. Could you please take a look?

You are right, after verification I found no abnormality, @spacewander what do you think?

spacewander commented 2 years ago

The add_header won't override the existent header. What about using a table to track headers, using set_header first and using add_header if the same header occurs again?

rampagecong commented 2 years ago

The add_header won't override the existent header. What about using a table to track headers, using set_header first and using add_header if the same header occurs again? I think it works.I'll try to fix it.

jthann commented 2 years ago

The problem still exists, not solved

goxiaoy commented 2 years ago

@jthann upgrade apisix to 2.14.0 or newer