cloudflare / pingora

A library for building fast, reliable and evolvable network services.
Apache License 2.0
21.4k stars 1.18k forks source link

pingora-proxy examples don't support pipelining #377

Open kenballus opened 3 weeks ago

kenballus commented 3 weeks ago

Describe the bug

The pingora-proxy examples don't support client-side HTTP pipelining.

Pingora info

Please include the following information about your environment:

Pingora version: e288bfe8f036d995d74367acef4b2fa0f04ecf26 (built from source) Rust version: cargo 1.79.0 (ffa9cf99a 2024-06-03) Operating system version: Debian 12

Steps to reproduce

  1. Build the pingora-proxy gateway example.
  2. Test that it works:
    printf 'GET / HTTP/1.1\r\nHost: one.one.one.one\r\n\r\n' \
    | ncat --no-shutdown localhost 6191 \
    | grep -oP 'HTTP/1.1 \d\d\d'
    HTTP/1.1 200
  3. Test that client-side connection reuse works when requests are not pipelined:
    (printf 'GET / HTTP/1.1\r\nHost: one.one.one.one\r\n\r\n'; sleep 1; printf 'GET / HTTP/1.1\r\nHost: one.one.one.one\r\n\r\n') \
    | ncat --no-shutdown localhost 6191 \
    | grep -oP 'HTTP/1.1 \d\d\d'
    HTTP/1.1 200
    HTTP/1.1 200
  4. Observe that connection reuse doesn't work when requests are pipelined:
    printf 'GET / HTTP/1.1\r\nHost: one.one.one.one\r\n\r\nGET / HTTP/1.1\r\nHost: one.one.one.one\r\n\r\n' \
    | ncat --no-shutdown localhost 6191 \
    | grep -oP 'HTTP/1.1 \d\d\d'
    HTTP/1.1 200

Expected results

I expect to get 2 responses when sending 2 pipelined requests.

Observed results

I only get 1 response.

eaufavor commented 2 weeks ago

Note that http pipelining is not supported by major browsers. Some also believe that it does more harm than good.

Ref https://en.wikipedia.org/wiki/HTTP_pipelining https://portswigger.net/research/browser-powered-desync-attacks https://community.f5.com/kb/technicalarticles/http-pipelining-a-security-risk-without-real-performance-benefits/286621

kenballus commented 2 weeks ago

Note that http pipelining is not supported by major browsers. Some also believe that it does more harm than good.

Yep. For better or for worse, HTTP is filled with features that seem useless or confusing in hindsight. Some of my (least) favorites are

Here's a breakdown of how other HTTP reverse proxies handle pipelined requests:

Disallow request pipelining:

Allow request pipelining, forward requests individually, then forward responses individually:

Allow request pipelining, forward requests individually, then forward responses pipelined:

In summary, request pipelining is supported in nearly all reverse proxies, but requests are always un-pipelined before forwarding.