diff options
author | haavardm <haavardm@opera.com> | 2015-06-11 01:19:54 -0700 |
---|---|---|
committer | Commit bot <commit-bot@chromium.org> | 2015-06-11 08:20:39 +0000 |
commit | 8e7ed88c4187c496961b87fdcd1a2c307c39fe1b (patch) | |
tree | c5f52bbcb033ca27404ddb067868e7112b55790b | |
parent | 8ca72d1504c20967ec2693ec453a5f13ae0926cf (diff) | |
download | chromium_src-8e7ed88c4187c496961b87fdcd1a2c307c39fe1b.zip chromium_src-8e7ed88c4187c496961b87fdcd1a2c307c39fe1b.tar.gz chromium_src-8e7ed88c4187c496961b87fdcd1a2c307c39fe1b.tar.bz2 |
Use net's response header parser for parsing multipart headers.
BUG=493379
Review URL: https://codereview.chromium.org/1166953002
Cr-Commit-Position: refs/heads/master@{#333909}
-rw-r--r-- | content/child/multipart_response_delegate.cc | 70 | ||||
-rw-r--r-- | net/http/http_util.cc | 24 | ||||
-rw-r--r-- | net/http/http_util.h | 11 | ||||
-rw-r--r-- | net/http/http_util_unittest.cc | 40 |
4 files changed, 96 insertions, 49 deletions
diff --git a/content/child/multipart_response_delegate.cc b/content/child/multipart_response_delegate.cc index c29fe55..ff8bd58 100644 --- a/content/child/multipart_response_delegate.cc +++ b/content/child/multipart_response_delegate.cc @@ -5,9 +5,11 @@ #include "content/child/multipart_response_delegate.h" #include "base/logging.h" +#include "base/memory/ref_counted.h" #include "base/strings/string_number_conversions.h" #include "base/strings/string_util.h" #include "net/base/net_util.h" +#include "net/http/http_response_headers.h" #include "net/http/http_util.h" #include "third_party/WebKit/public/platform/WebHTTPHeaderVisitor.h" #include "third_party/WebKit/public/platform/WebString.h" @@ -209,59 +211,47 @@ int MultipartResponseDelegate::PushOverLine(const std::string& data, } bool MultipartResponseDelegate::ParseHeaders() { - int line_feed_increment = 1; - - // Grab the headers being liberal about line endings. - size_t line_start_pos = 0; - size_t line_end_pos = data_.find('\n'); - while (line_end_pos != std::string::npos) { - // Handle CRLF - if (line_end_pos > line_start_pos && data_[line_end_pos - 1] == '\r') { - line_feed_increment = 2; - --line_end_pos; - } else { - line_feed_increment = 1; - } - if (line_start_pos == line_end_pos) { - // A blank line, end of headers - line_end_pos += line_feed_increment; - break; - } - // Find the next header line. - line_start_pos = line_end_pos + line_feed_increment; - line_end_pos = data_.find('\n', line_start_pos); - } - // Truncated in the middle of a header, stop parsing. - if (line_end_pos == std::string::npos) + int headers_end_pos = net::HttpUtil::LocateEndOfAdditionalHeaders( + data_.c_str(), data_.size(), 0); + + if (headers_end_pos < 0) return false; - // Eat headers - std::string headers("\n"); - headers.append(data_, 0, line_end_pos); - data_ = data_.substr(line_end_pos); + // Eat headers and prepend a status line as is required by + // HttpResponseHeaders. + std::string headers("HTTP/1.1 200 OK\r\n"); + headers.append(data_, 0, headers_end_pos); + data_ = data_.substr(headers_end_pos); + + scoped_refptr<net::HttpResponseHeaders> response_headers = + new net::HttpResponseHeaders( + net::HttpUtil::AssembleRawHeaders(headers.c_str(), headers.size())); // Create a WebURLResponse based on the original set of headers + the - // replacement headers. We only replace the same few headers that gecko - // does. See netwerk/streamconv/converters/nsMultiMixedConv.cpp. - std::string content_type = net::GetSpecificHeader(headers, "content-type"); - std::string mime_type; - std::string charset; - bool has_charset = false; - net::HttpUtil::ParseContentType(content_type, &mime_type, &charset, - &has_charset, NULL); + // replacement headers. We only replace the same few headers that gecko + // does. See netwerk/streamconv/converters/nsMultiMixedConv.cpp. WebURLResponse response(original_response_.url()); + + std::string mime_type; + response_headers->GetMimeType(&mime_type); response.setMIMEType(WebString::fromUTF8(mime_type)); + + std::string charset; + response_headers->GetCharset(&charset); response.setTextEncodingName(WebString::fromUTF8(charset)); + // Copy the response headers from the original response. HeaderCopier copier(&response); original_response_.visitHTTPHeaderFields(&copier); + // Replace original headers with multipart headers listed in kReplaceHeaders. for (size_t i = 0; i < arraysize(kReplaceHeaders); ++i) { std::string name(kReplaceHeaders[i]); - std::string value = net::GetSpecificHeader(headers, name); - if (!value.empty()) { - response.setHTTPHeaderField(WebString::fromUTF8(name), - WebString::fromUTF8(value)); + std::string value; + void* iterator = nullptr; + while (response_headers->EnumerateHeader(&iterator, name, &value)) { + response.addHTTPHeaderField(WebString::fromLatin1(name), + WebString::fromLatin1(value)); } } // To avoid recording every multipart load as a separate visit in diff --git a/net/http/http_util.cc b/net/http/http_util.cc index a22ee60..fa40ed7 100644 --- a/net/http/http_util.cc +++ b/net/http/http_util.cc @@ -544,9 +544,19 @@ int HttpUtil::LocateStartOfStatusLine(const char* buf, int buf_len) { return -1; // Not found } -int HttpUtil::LocateEndOfHeaders(const char* buf, int buf_len, int i) { - bool was_lf = false; +static int LocateEndOfHeadersHelper(const char* buf, + int buf_len, + int i, + bool accept_empty_header_list) { char last_c = '\0'; + bool was_lf = false; + if (accept_empty_header_list) { + // Normally two line breaks signal the end of a header list. An empty header + // list ends with a single line break at the start of the buffer. + last_c = '\n'; + was_lf = true; + } + for (; i < buf_len; ++i) { char c = buf[i]; if (c == '\n') { @@ -561,6 +571,16 @@ int HttpUtil::LocateEndOfHeaders(const char* buf, int buf_len, int i) { return -1; } +int HttpUtil::LocateEndOfAdditionalHeaders(const char* buf, + int buf_len, + int i) { + return LocateEndOfHeadersHelper(buf, buf_len, i, true); +} + +int HttpUtil::LocateEndOfHeaders(const char* buf, int buf_len, int i) { + return LocateEndOfHeadersHelper(buf, buf_len, i, false); +} + // In order for a line to be continuable, it must specify a // non-blank header-name. Line continuations are specifically for // header values -- do not allow headers names to span lines. diff --git a/net/http/http_util.h b/net/http/http_util.h index b158524..79a41ac 100644 --- a/net/http/http_util.h +++ b/net/http/http_util.h @@ -147,10 +147,19 @@ class NET_EXPORT HttpUtil { // 2616 defines the end-of-headers marker as a double CRLF; however, some // servers only send back LFs (e.g., Unix-based CGI scripts written using the // ASIS Apache module). This function therefore accepts the pattern LF[CR]LF - // as end-of-headers (just like Mozilla). + // as end-of-headers (just like Mozilla). The first line of |buf| is + // considered the status line, even if empty. // The parameter |i| is the offset within |buf| to begin searching from. static int LocateEndOfHeaders(const char* buf, int buf_len, int i = 0); + // Same as |LocateEndOfHeaders|, but does not expect a status line, so can be + // used on multi-part responses or HTTP/1.x trailers. As a result, if |buf| + // starts with a single [CR]LF, it is considered an empty header list, as + // opposed to an empty status line above a header list. + static int LocateEndOfAdditionalHeaders(const char* buf, + int buf_len, + int i = 0); + // Assemble "raw headers" in the format required by HttpResponseHeaders. // This involves normalizing line terminators, converting [CR]LF to \0 and // handling HTTP line continuations (i.e., lines starting with LWS are diff --git a/net/http/http_util_unittest.cc b/net/http/http_util_unittest.cc index 980c388..8d0a219 100644 --- a/net/http/http_util_unittest.cc +++ b/net/http/http_util_unittest.cc @@ -267,12 +267,17 @@ TEST(HttpUtilTest, LocateEndOfHeaders) { const char* const input; int expected_result; } tests[] = { - { "foo\r\nbar\r\n\r\n", 12 }, - { "foo\nbar\n\n", 9 }, - { "foo\r\nbar\r\n\r\njunk", 12 }, - { "foo\nbar\n\njunk", 9 }, - { "foo\nbar\n\r\njunk", 10 }, - { "foo\nbar\r\n\njunk", 10 }, + {"\r\n", -1}, + {"\n", -1}, + {"\r", -1}, + {"foo", -1}, + {"\r\n\r\n", 4}, + {"foo\r\nbar\r\n\r\n", 12}, + {"foo\nbar\n\n", 9}, + {"foo\r\nbar\r\n\r\njunk", 12}, + {"foo\nbar\n\njunk", 9}, + {"foo\nbar\n\r\njunk", 10}, + {"foo\nbar\r\n\njunk", 10}, }; for (size_t i = 0; i < arraysize(tests); ++i) { int input_len = static_cast<int>(strlen(tests[i].input)); @@ -281,6 +286,29 @@ TEST(HttpUtilTest, LocateEndOfHeaders) { } } +TEST(HttpUtilTest, LocateEndOfAdditionalHeaders) { + struct { + const char* const input; + int expected_result; + } tests[] = { + {"\r\n", 2}, + {"\n", 1}, + {"\r", -1}, + {"foo", -1}, + {"\r\n\r\n", 2}, + {"foo\r\nbar\r\n\r\n", 12}, + {"foo\nbar\n\n", 9}, + {"foo\r\nbar\r\n\r\njunk", 12}, + {"foo\nbar\n\njunk", 9}, + {"foo\nbar\n\r\njunk", 10}, + {"foo\nbar\r\n\njunk", 10}, + }; + for (size_t i = 0; i < arraysize(tests); ++i) { + int input_len = static_cast<int>(strlen(tests[i].input)); + int eoh = HttpUtil::LocateEndOfAdditionalHeaders(tests[i].input, input_len); + EXPECT_EQ(tests[i].expected_result, eoh); + } +} TEST(HttpUtilTest, AssembleRawHeaders) { struct { const char* const input; // with '|' representing '\0' |