apache / apisix-java-plugin-runner

APISIX Plugin Runner in Java
https://apisix.apache.org/
Apache License 2.0
126 stars 95 forks source link

bug: ext-plugin-post-resp can't get duplicate headers from upstream response, such as Set-Cookie #262

Open youth-lee opened 11 months ago

youth-lee commented 11 months ago

Environment

Steps to reproduce the issue

  1. use ext-plugin-post-resp postFilter(PostRequest request, PostResponse response, PluginFilterChain chain)
  2. use request.getUpstreamHeaders() to get headers
  3. upstream response
    Set-Cookie: rememberMe=deleteMe; Path=/; Max-Age=0; Expires=Sat, 19-Aug-2023 05:45:05 GMT
    Set-Cookie: JSESSIONID=deleteMe; Path=/; Max-Age=0; Expires=Sat, 19-Aug-2023 05:45:05 GMT
    Set-Cookie: JSESSIONID=0bc8714b-e1bf-4077-baaa-b94c8ba10a05; Path=/; HttpOnly
    Set-Cookie: rememberMe=deleteMe; Path=/; Max-Age=0; Expires=Sat, 19-Aug-2023 05:45:05 GMT

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

    just get the last Set-Cookie item Set-Cookie: rememberMe=deleteMe; Path=/; Max-Age=0; Expires=Sat, 19-Aug-2023 05:45:05 GMT

What's the expected result?

  1. can get duplicate headers with Multimap data structure
  2. can set duplicate headers

One more thing!

It is recommended that ext-plugin-post-resp inherits all the headers of upstream by default, so you don't need to write them again in the plugin.

eg:

  1. upstream return content-type = text/html
  2. empty code in postFilter(PostRequest request, PostResponse response, PluginFilterChain chain)
  3. the client get content-type = text/pain
gaoxingliang commented 10 months ago

@youth-lee As a workaround you can refer to the code in: https://github.com/gaoxingliang/apisix-java-plugin-runner/blob/encrypt-response/runner-plugin-sdk/src/main/java/org/apache/apisix/plugin/runner/PostRequest.java#L88

I added one method to return a map of list values. and then in the filter: https://github.com/gaoxingliang/apisix-java-plugin-runner/blob/encrypt-response/runner-starter/src/main/java/org/apache/apisix/plugin/runner/EncryptResponseFilter.java#L30 it will get the upstream response headers correctly.

If you donot want to change the code, you can do the java reflect in your code and get the req and do the parse.

The below code is an example in python to add two headers:

from http.server import BaseHTTPRequestHandler, HTTPServer

class CustomRequestHandler(BaseHTTPRequestHandler):
    def do_GET(self):
        self.send_response(200)
        self.send_header('Content-type', 'application/json')
        self.send_header('Custom-Header', 'Custom Value')
        self.send_header('header1', 'v1')
        self.send_header('header1', 'v2')
        self.end_headers()

        response = '{"message": "Hello, world!"}'
        self.wfile.write(response.encode('utf-8'))

def run_server():
    host = '0.0.0.0'
    port = 8100

    server = HTTPServer((host, port), CustomRequestHandler)
    server.serve_forever()

if __name__ == '__main__':
    run_server()

and below is the log it printed:

 2023-09-22 06:10:35,919 INFO  epollEventLoopGroup-2-2          - req headers: {Content-type=application/json, header1=v2, Custom-Header=Custom Value, Server=BaseHTTP/0.6 Python/3.6.8, Date=Fri, 22 Sep 2023 06:10:35 GMT}
 2023-09-22 06:10:35,920 INFO  epollEventLoopGroup-2-2          - req headers map:{Content-type=[application/json], header1=[v1, v2], Server=[BaseHTTP/0.6 Python/3.6.8], Custom-Header=[Custom Value], Date=[Fri, 22 Sep 2023 06:10:35 GMT]}