diff --git a/proxy_server.rb b/proxy_server.rb index cbb1ede..ec1f5dd 100644 --- a/proxy_server.rb +++ b/proxy_server.rb @@ -19,6 +19,15 @@ class ProxyServer < Sinatra::Base ENV.fetch("JWT_SIGNING_PUBLIC_KEY").gsub("\\n", "\n") ).freeze + # Remove some headers from proxied requests. + HEADERS_SKIP_FORWARD = [ + "set-cookie", # Don't forward authenticated cookies data + "transfer-encoding" # Don't forward transfer-encoding as this is a + # “hop-by-hop” header which needs to be + # consumed by the proxy when reading the + # target response. + ].freeze + TOKEN_HEADER = ENV.fetch( "CORS_TOUJOURS_TOKEN_HEADER_NAME", "x-cors-toujours-token" @@ -119,6 +128,12 @@ def path_matches_pattern?(actual_path, pattern_path) Regexp.new(pattern_regex).match?(actual_path) end + def skip_header?(key) + HEADERS_SKIP_FORWARD.any? do |header| + key.downcase.start_with?(header) + end + end + def forward_request(method) target_url = request.fullpath[1..].gsub(":/", "://") uri = URI.parse(target_url) @@ -160,18 +175,29 @@ def forward_request(method) # Execute the request to the target server Net::HTTP.start(uri.hostname, uri.port, use_ssl: uri.scheme == "https") do |http| + # This has the effect to .read the response body directly. In + # case we want to stream the response we might want to use a + # block with http.request(..) do |response| at some + # point. Especially when we will want to proxy file download + # requests. response = http.request(target_request) - # Pass the target server response back to the client + # Forward the raw target response back to the client. + + # RESPONSE CODE status response.code - headers "Content-Type" => response.content_type - content_encoding = response.get_fields "content-encoding" - if content_encoding && content_encoding.include?("gzip") - body Zlib::GzipReader.new(StringIO.new(response.body)).read - else - body response.body + forwarded_headers = {} + response.each_header do |key, value| + next if skip_header?(key) + + forwarded_headers[key] = value end + # RESPONSE HEADERS + headers forwarded_headers + + # RESPONSE BODY + body response.body end end end diff --git a/spec/proxy_server_spec.rb b/spec/proxy_server_spec.rb index 9cfb39f..f983445 100644 --- a/spec/proxy_server_spec.rb +++ b/spec/proxy_server_spec.rb @@ -55,7 +55,15 @@ def expect_json_body(k, v) before(:each) do stub_request(:get, "https://jsonplaceholder.typicode.com/posts") .with(headers: {"x-foo": "bar"}) - .to_return(status: 200, body: "", headers: {}) + .to_return( + status: 200, + body: "", + headers: { + "X-Target-Resp-Header": "Custom", + "Set-Cookie": "session=remove", + "Transfer-Encoding": "chunked" + } + ) end context "preflight request" do @@ -96,6 +104,12 @@ def expect_json_body(k, v) expect(last_response.status).to eq(200) end + it "fowards most headers but skips cookies and transfer encoding" do + expect(last_response["X-Target-Resp-Header"]).to eq("Custom") + expect(last_response["Set-Cookie"]).to be_nil + expect(last_response["Transfer-Encoding"]).to be_nil + end + context "when header name is changed via configuration" do before(:each) do stub_const('ProxyServer::TOKEN_HEADER', "x-custom-proxy")