-
-
Notifications
You must be signed in to change notification settings - Fork 58
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
warcio mangles non-ASCII HTTP headers #128
Comments
Yeah, this is tricky... First, the API isn't quite correct, it should really be:
but it seems like the result is the same. The %-encoding was implemented to deal with ambiguity, as even though ISO-8859-1 is supported to be the encoding for headers, servers can and do use UTF-8, and probably other encodings. In python its standard to represent headers as Unicode strings, so with Python 3, this is an issue. The %-encoding was designed to remove that ambiguity when serializing headers. The default %-encoding via
It seems like the implementation was geared towards content-disposition and similar uses of UTF-8. One option is to add the charset prefix, but not sure this is correct either (this is for multi-value headers, I think)
or
Probably it should just be:
Maybe an encoding param is also needed here... |
Hmm, yeah, but there is even a test for a single payload with the headers included in the test suite, so I assumed that usage was also fine: Lines 356 to 368 in aa702cb
Unfortunately, the documentation for warcio's APIs is lacking, so it's often hard to tell what is and isn't supported usage.
I disagree. Yes, there is ambiguity, but that only matters when trying to consume HTTP. The data written to WARC response records is 'the full HTTP response received over the network' (or '... request sent ...' for request records). As such, no manipulation should ever happen to that data. Your proposed percent encoding would be equivalent per the HTTP spec, but it still wouldn't be what was sent/received over the network. In other words, representing the headers like that in the |
You're right, sorry, I forgot about that support, its been a while :)
Yeah, it's tricky because warcio serves a dual role here, both for parsing data from existing WARCs, where the HTTP semantics are important, as well as writing raw data. An option could be to add a flag, say raw mode, that uses I don't have a lot of time to focus on this now unfortunately, but if you have other suggestions, or want to open a PR, can review it |
I'd argue that #45 does not actually fix #38 at all. Reading a WARC record and then writing it again should produce identical record body data (though it may change the WARC headers to an equivalent representation), i.e. the HTTP headers should not be reencoded in that scenario either. Essentially, reading the response record from a WARC is equivalent to reading from a network connection with the actual server. I think the only sane approach is to avoid the round trip to the mapping and back to bytes entirely. I haven't thought this through completely, but my idea right now would be to have |
@JustAnotherArchivist is right. Warcio fails to decode and reencode again this file for example:
Notice the Set-Cookie header, where the name before the "=" has non-ascii characters. I agree this is not compliant nor common, but warcio should be able to deal with all sorts of WARC files archived in different manner. Instead, this error happens:
in warcio/warcio/statusandheaders.py Line 179 in aa702cb
|
I agree that this is a real bug. I don't think I have this tested in the "warcio check" branch, either! If you look at the WARC standard it's a bit complicated to figure out what you're really supposed to do in this case, so there should be no surprise that there are buggy implementations out there. But it's very obvious what is meant. |
Yeah, I think as @JustAnotherArchivist points out in #128 (comment), probably the only real solution is to avoid changing the encoding at all and always treat the headers as bytes, and let the browser handle it for replay. The initial idea was to be in line with how Python 3 treats headers (as strings), and %-encode any non-ascii characters, but that clearly will not work if we want to allow invalid headers as they are, which probably does make sense. |
I created a pull request with a temporary fix so at least WARCIO doesn't terminate when this happens. |
Yes, this is serious problem. I've encountered warcio breaking when trying to convert old arcs to warcs. The issue #88 is one example how warcio breaks. It happens in warcio/warcio/statusandheaders.py Lines 203 to 206 in aa702cb
.sub happens, but afterwards quoting doesn't (because curr_value isn't new_value) and afterwards this header breaks with UnicodeError on the line warcio/warcio/statusandheaders.py Line 179 in aa702cb
I also suggest that headers should just stay as they are, because it's not warcios job to fix the multitude of problems some web servers might cause in the headers. Warcio can ofc be used to fix the headers if there are functional problems in playback, but in main usage it shouldn't try to fix everything. (Even though RFCs defining HTTP headers have stuff like "Historically, HTTP has allowed field content with text in the ISO-8859-1 charset [ISO-8859-1], supporting other charsets only through use of [RFC2047] encoding. In practice, most HTTP header field values use only a subset of the US-ASCII charset [USASCII]. Newly defined header fields SHOULD limit their field values to US-ASCII octets. A recipient SHOULD treat other octets in field content (obs-text) as opaque data.") |
I discovered today that warcio mangles the HTTP header data when it isn't pure ASCII. Specifically, I am dealing with a server that returns ISO-8859-1 headers.
As far as I can tell, this behaviour was introduced by #45 in warcio 1.6.0. I suspect that it's fine for reading WARCs, but it's absolutely horrible for writing because the WARCs will not contain the data as sent by the server (nor even data that would be considered equivalent per HTTP!), hence violating the WARC specification.
Example:
Expected output for the relevant header:
X-non-utf8-value: <0xFF>
(where<0xFF>
is that literal byte)Actual output:
X-non-utf8-value: %C3%BF
The text was updated successfully, but these errors were encountered: