Closed surajprak closed 2 years ago
Here is the hex dump of response
48, 54, 54, 50, 2F, 31, 2E, 31, 20, 32, 30, 30, 20, 4F, 4B, 0, D, A, 53, 65, 72, 76, 65, 72, 3A, 20, 4D, 65, 73, 73, 79, D, A, 44, 61, 74, 65, 3A, 20, 46, 72, 69, 2C, 20, 33, 31, 20, 41, 75, 67, 20, 32, 30, 31, 31, 20, 30, 30, 3A, 33, 31, 3A, 35, 33, 20, 47, 4D, 54, D, A, 43, 6F, 6E, 74, 65, 6E, 74, 2D, 54, 79, 70, 65, 3A, 20, 74, 65, 78, 74, 2F, 68, 74, 6D, 6C, D, A, 43, 6F, 6E, 6E, 65, 63, 74, 69, 6F, 6E, 3A, 20, 4B, 65, 65, 70, 2D, 41, 6C, 69, 76, 65, D, A, 43, 6F, 6E, 74, 65, 6E, 74, 2D, 4C, 65, 6E, 67, 74, 68, 3A, 20, 31, 35, D, A, D, A, 32, 30, 31, 39, 36, 39, 38, 34, 38, 35, 38, 30, D, A, 0
On further investigation, in httparse library
/// From [RFC 7230](https://tools.ietf.org/html/rfc7230):
///
/// > ```notrust
/// > reason-phrase = *( HTAB / SP / VCHAR / obs-text )
/// > HTAB = %x09 ; horizontal tab
/// > VCHAR = %x21-7E ; visible (printing) characters
/// > obs-text = %x80-FF
/// > ```
///
/// > A.2. Changes from RFC 2616
/// >
/// > Non-US-ASCII content in header fields and the reason phrase
/// > has been obsoleted and made opaque (the TEXT rule was removed).
///
/// Note that the following implementation deliberately rejects the obsoleted (non-US-ASCII) text range.
///
/// The fully compliant parser should probably just return the reason-phrase as an opaque &[u8] data
/// and leave interpretation to user or specialized helpers (akin to .display() in std::path::Path)
#[inline]
fn parse_reason<'a>(bytes: &mut Bytes<'a>) -> Result<&'a str> {
loop {
let b = next!(bytes);
if b == b'\r' {
expect!(bytes.next() == b'\n' => Err(Error::Status));
return Ok(Status::Complete(unsafe {
// all bytes up till `i` must have been HTAB / SP / VCHAR
str::from_utf8_unchecked(bytes.slice_skip(2))
}));
} else if b == b'\n' {
return Ok(Status::Complete(unsafe {
// all bytes up till `i` must have been HTAB / SP / VCHAR
str::from_utf8_unchecked(bytes.slice_skip(1))
}));
} **else if !((b >= 0x20 && b <= 0x7E) || b == b'\t') {
return Err(Error::Status);
}**
}
}
Since, we have a 00 in request 48, 54, 54, 50, 2F, 31, 2E, 31, 20, 32, 30, 30, 20, 4F, 4B, 0, D, A else if !((b >= 0x20 && b <= 0x7E) || b == b'\t') check is true and its returning as error. Shall we allow 0 (null) char as a valid one?
Other libraries like python requests, curl is allowing it.
Hrm, even if we weren't as strict and supported obs-text, that would still exclude byte 0... What servers put a null byte in the status code??
Ha ha, its actually coming from the server of a very big international bank and most likely its C-string which they are trying to concat. It will be a time taking exercise to convince them of changing their server. Moreover, they will say that parser in other languages are supporting it. Is their a work around for this?
Chrome rejects NUL anywhere in a response head, let's close this.
Here is my hyper trace
TRACE hyper::client::pool > checkout waiting for idle connection: "http://10.200.14.75:8000" TRACE hyper::client::connect::http > Http::connect; scheme=http, host=10.200.14.75, port=Some(8000) DEBUG hyper::client::connect::http > connecting to 10.200.14.75:8000 DEBUG hyper::client::connect::http > connected to Some(V4(10.200.14.75:8000)) TRACE hyper::client::conn > client handshake HTTP/1 TRACE hyper::client > handshake complete, spawning background dispatcher task TRACE hyper::proto::h1::conn > flushed({role=client}): State { reading: Init, writing: Init, keep_alive: Busy } TRACE hyper::client::pool > checkout dropped for "http://10.200.14.75:8000" TRACE hyper::proto::h1::role > Client::encode method=POST, body=Some(Known(6)) DEBUG hyper::proto::h1::io > flushed 152 bytes TRACE hyper::proto::h1::conn > flushed({role=client}): State { reading: Init, writing: KeepAlive, keep_alive: Busy } TRACE hyper::proto::h1::conn > Conn::read_head DEBUG hyper::proto::h1::io > read 172 bytes TRACE hyper::proto::h1::role > Response.parse([Header; 100], [u8; 172]) TRACE hyper::proto::h1::conn > State::close_read() DEBUG hyper::proto::h1::conn > parse error (invalid HTTP status-code parsed) with 172 bytes DEBUG hyper::proto::h1::dispatch > read_head error: invalid HTTP status-code parsed Error invalid HTTP status-code parsed TRACE hyper::proto::h1::conn > State::close() TRACE hyper::proto::h1::conn > flushed({role=client}): State { reading: Closed, writing: Closed, keep_alive: Disabled } TRACE hyper::proto::h1::conn > shut down IO complete
Same call works fine with curl cmd
curl -d 'abcdef1234abcdef=27062019112303|' http://10.200.14.75:8000 -v
Any idea what is wrong here. My rust code is