pingora icon indicating copy to clipboard operation
pingora copied to clipboard

Gateway example forwards requests with multiple `Content-Length` headers

Open kenballus opened this issue 1 year ago • 1 comments

Describe the bug

The gateway example forwards requests with multiple Content-Length headers. The HTTP RFCs say not to forward such messages.

From RFC 7230:

If a message is received without Transfer-Encoding and with either multiple Content-Length header fields having differing field-values or a single Content-Length header field having an invalid value, then the message framing is invalid and the recipient MUST treat it as an unrecoverable error. If this is a request message, the server MUST respond with a 400 (Bad Request) status code and then close the connection.

Thus, upon receipt of a request with multiple Content-Length headers, the gateway example should reject the request with a 400.

Pingora info

Please include the following information about your environment:

Pingora version: 648a6ad0554442be5f9c8d396a66843552156d1f Rust version: cargo 1.79.0 (ffa9cf99a 2024-06-03) Operating system version: Debian 13

Steps to reproduce

  1. Get a fresh Debian container:
docker run --rm -it debian:trixie-slim
  1. Install dependencies:
apt -y update && apt -y upgrade && apt -y install ncat clang git curl cmake g++ && curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh -s -- -y && . ~/.cargo/env
  1. Clone and build Pingora:
git clone 'https://github.com/cloudflare/pingora' && cd pingora && cargo build --example gateway
  1. Run the gateway:
./target/debug/examples/gateway &
  1. Send a control request, and observe that it works as expected:
(printf 'GET / HTTP/1.1\r\nContent-Length: 1\r\nHost: one.one.one.one\r\n\r\nZ'; sleep 1) | ncat localhost 6191
  1. Add an extra Content-Length header, and send it again:
(printf 'GET / HTTP/1.1\r\nContent-Length: 1\r\nContent-Length: 0\r\nHost: one.one.one.one\r\n\r\nZ'; sleep 1) | ncat localhost 6191

Expected results

Pingora should respond 400.

Observed results

Pingora forwarded the request to one.one.one.one, which responds 400. This is clear because the response has a CF-RAY header, which Pingora wouldn't insert on its own.

kenballus avatar Jun 26 '24 15:06 kenballus

More reference https://datatracker.ietf.org/doc/html/rfc9112#section-6.3

eaufavor avatar Jun 28 '24 16:06 eaufavor