seanmonstar / reqwest

An easy and powerful Rust HTTP Client
https://docs.rs/reqwest
Apache License 2.0
9.99k stars 1.13k forks source link

RusTLS with Client Certificate, cannot parse the response body #1769

Open dgsantana opened 1 year ago

dgsantana commented 1 year ago

I'm hitting a very weird case. When using NativeTLS the same exact code works, and I can get the body from the response either text() or bytes(). But when using RusTLS (and I need too due to the certificates I'm required to use), it always fails and says it's EOF, but I can see that reqwest did received all the response.

The expected response body is:

<?xml version='1.0' ?>\n<env:Envelope xmlns:env='http://www.w3.org/2003/05/soap-envelope'>\n<env:Body>\n<env:Fault>\n<env:Code>\n<env:Value>\nenv:Receiver</env:Value>\n</env:Code>\n<env:Reason>\n<env:Text xml:lang=\"en-US\">

The log when using RusTLS (ignore the fact of the 500 Error, it's the same in NativeTLS)

2023-03-08T21:53:22.941407Z DEBUG hyper::proto::h1::io: flushed 1813 bytes
2023-03-08T21:53:22.941500Z TRACE hyper::proto::h1::conn: flushed({role=client}): State { reading: Init, writing: KeepAlive, keep_alive: Busy }
2023-03-08T21:53:25.957706Z TRACE hyper::proto::h1::conn: Conn::read_head
2023-03-08T21:53:25.957976Z TRACE reqwest::connect::verbose: 1f811461 read: b"HTTP/1.1 500 Error\r\nContent-Type: application/soap+xml; charset=utf-8\r\nX-Backside-Transport: FAIL FAIL\r\nConnection: close\r\nStrict-Transport-Security: max-age=31536000; includeSubDomains\r\n\r\n<?xml version='1.0' ?>\n<env:Envelope xmlns:env='http://www.w3.org/2003/05/soap-envelope'>\n<env:Body>\n<env:Fault>\n<env:Code>\n<env:Value>\nenv:Receiver</env:Value>\n</env:Code>\n<env:Reason>\n<env:Text xml:lang=\"en-US\">\nInternal Error (from server)\n</env:Text>\n</env:Reason>\n</env:Fault>\n</env:Body>\n</env:Envelope>\n"
2023-03-08T21:53:25.958190Z TRACE hyper::proto::h1::io: received 499 bytes
2023-03-08T21:53:25.958359Z TRACE parse_headers: hyper::proto::h1::role: Response.parse bytes=499
2023-03-08T21:53:25.958517Z TRACE parse_headers: hyper::proto::h1::role: Response.parse Complete(189)
2023-03-08T21:53:25.958766Z TRACE parse_headers: hyper::proto::h1::role: neither Transfer-Encoding nor Content-Length
2023-03-08T21:53:25.958915Z DEBUG hyper::proto::h1::io: parsed 4 headers
2023-03-08T21:53:25.959011Z DEBUG hyper::proto::h1::conn: incoming body is close-delimited
2023-03-08T21:53:25.959112Z TRACE hyper::proto::h1::conn: remote disabling keep-alive
2023-03-08T21:53:25.959289Z TRACE hyper::proto::h1::decode: decode; state=Eof(false)
2023-03-08T21:53:25.959424Z TRACE hyper::proto::h1::conn: flushed({role=client}): State { reading: Body(Eof(false)), writing: KeepAlive, keep_alive: Disabled }
2023-03-08T21:53:25.959556Z TRACE hyper::proto::h1::decode: decode; state=Eof(false)
2023-03-08T21:53:25.959679Z DEBUG hyper::proto::h1::conn: incoming body decode error: unexpected end of file
2023-03-08T21:53:25.959783Z TRACE hyper::proto::h1::conn: State::close()

PS: I don't have control over the server.

seanmonstar commented 1 year ago

I suspect that the UnexpectedEof comes from rustls, perhaps saying that the it didn't properly end the TLS message.

dgsantana commented 1 year ago

Probably, for any Status 200 it seems rustls completes the read operation. But I do need to get the body of the 500 status message :).

djc commented 9 months ago

This sounds like it might be similar to https://github.com/hyperium/hyper/issues/3427, but for the HTTP/1 case.