pingora icon indicating copy to clipboard operation
pingora copied to clipboard

When I attempt to issue an HTTP Redirect from request_filter the connection hangs

Open pszabop opened this issue 1 year ago • 4 comments

Describe the bug

I'm attempting to issue an HTTP redirect from request_filter()

With the code shown below the connection hangs.

There needs to be a way to issue something besides errors from the filters. Perhaps the docs are missing a working example, or perhaps this a feature request, I cannot tell.

Pingora info

Pingora version: 0.3 (from crate) Rust version: cargo 1.83.0 (5ffbef321 2024-10-29) Operating system version: Docker for OSX, 20.10.17

Steps to reproduce

Using example Proxy HTTP for LB, the following code for request_filter

use url::Url;
use pingora::proxy::{ProxyHttp, Session};
use pingora_http::{ResponseHeader, StatusCode};

async fn request_filter(&self, session: &mut Session, ctx: &mut Self::CTX) -> Result<bool> {
    // Construct the redirect URL with the return_url parameter
    let request = session.req_header();
    let current_url = request.uri.to_string();
    let scheme = request.uri.scheme_str().unwrap_or("http");
    let host = request.uri.host().unwrap_or("localhost");
    let port = session.req_header().uri.port_u16().unwrap_or(80);
    let mut redirect_url = Url::parse(&format!("{}://{}:{}/redirect_test_path", scheme, host, port)).unwrap();
    redirect_url.query_pairs_mut().append_pair("return_url", &current_url); 

    // Create the response with the Location header
    let mut response = ResponseHeader::build(StatusCode::FOUND, None).unwrap();
    response.insert_header("Location", redirect_url.as_str());

    // Write the response header
    session.write_response_header(Box::new(response), true).await?;
    session.write_response_body(None, true).await?;
    return Ok(true);
}

Expected results

a curl -v should show the redirect and should exit.

Observed results

$ curl -v --max-redirs 0 localhost:6190
*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to localhost (127.0.0.1) port 6190 (#0)
> GET / HTTP/1.1
> Host: localhost:6190
> User-Agent: curl/7.64.1
> Accept: */*
> 
< HTTP/1.1 302 Found
< Location: http://localhost/redirect_test_path?return_url=%2F
< Date: Sat, 28 Dec 2024 02:27:44 GMT
< Connection: keep-alive
* no chunk, no close, no size. Assume close to signal end

Additional context

pszabop avatar Dec 28 '24 02:12 pszabop

Try to set content-length of response body.

response.insert_header(
    "Content-Length",
    "0".to_string(),
);

vicanso avatar Dec 28 '24 02:12 vicanso

Yep, that did it. So this is a documentation request or a "pick suitable defaults for responses when request_filter returns Ok(true)"

pszabop avatar Dec 28 '24 06:12 pszabop

Updated documentation for this trait method here https://github.com/cloudflare/pingora/pull/613.

kumarlokesh avatar May 13 '25 19:05 kumarlokesh

@kumarlokesh thank you! I ran into this same issue when trying to filter a request with Ok(true) this led to a seemingly infinite hanging request. Setting

if condition {
    session.set_keepalive(None);
    return Ok(true);
}

was the fix as you noted is in #613 I think the documentation can be improved on this. That using request_filter() alone is likely not enough. Particularly, I was looking at the phase chart for what to do after filtering a request

JosiahParry avatar Jun 29 '25 15:06 JosiahParry