Skip to content

Pingora forwards Connection headers to upstream servers #706

@nojima

Description

@nojima

Describe the bug

The Connection header is a hop-by-hop header, and proxy servers should not forward it. However, Pingora appears to forward the Connection header from the client directly to the upstream server.

For example, if a client sends Connection: close, Pingora will forward Connection: close to the upstream server. In some environments, this may cause the connection between Pingora and the upstream to be closed, which can lead to performance issues.

I also tested the hop-by-hop headers listed in RFC 2616, and all of them were forwarded to the upstream server without modification.

Pingora info

Pingora version: 0.6.0
Rust version: 1.90.0
Operating system version: Ubuntu 22.04

Steps to reproduce

This is the source code of the load balancer. It simply proxies the request to localhost:3000.

use async_trait::async_trait;
use pingora::prelude::*;

struct LB;

#[async_trait]
impl ProxyHttp for LB {
    type CTX = ();
    fn new_ctx(&self) -> Self::CTX {}

    async fn upstream_peer(&self, _session: &mut Session, _ctx: &mut ()) -> Result<Box<HttpPeer>> {
        let peer = HttpPeer::new("127.0.0.1:3000", false, "".to_string());
        Ok(Box::new(peer))
    }
}

fn main() -> pingora::Result<()> {
    env_logger::init();

    let mut my_server = Server::new(None)?;
    my_server.bootstrap();

    let mut lb = http_proxy_service(&my_server.configuration, LB);
    lb.add_tcp("[::]:8000");
    my_server.add_service(lb);

    my_server.run_forever();
}

Start this server.

In another shell, start a TCP server by using socat. Note that this server never returns a response.

socat TCP-LISTEN:3000,reuseaddr,fork -

Send an HTTP request like the following from another shell. Then, socat will print the HTTP request sent from Pingora.

nc -C localhost 8000 <<'EOF'
GET / HTTP/1.1
Host: example.com
Connection: close

EOF

Expected results

The upstream server should not receive Connection: close header given by the client.

GET / HTTP/1.1
Host: example.com

Observed results

socat outputs the following text, which is a HTTP request sent from Pingora to the upstream server.

GET / HTTP/1.1
Host: example.com
Connection: close

Connection: close is included in the request.

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions