diff options
author | ericroman@google.com <ericroman@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-09-06 01:00:53 +0000 |
---|---|---|
committer | ericroman@google.com <ericroman@google.com@0039d316-1c4b-4281-b951-d872f2087c98> | 2008-09-06 01:00:53 +0000 |
commit | 036d87726035ac500ba35ab41fdc9ef6128f0e4f (patch) | |
tree | 48f2abffad974fd7599616cd2fa7888f2a5d7fe8 /net/http/http_util.cc | |
parent | 9b323e40ae67692745459f68920f5dab61aaaed3 (diff) | |
download | chromium_src-036d87726035ac500ba35ab41fdc9ef6128f0e4f.zip chromium_src-036d87726035ac500ba35ab41fdc9ef6128f0e4f.tar.gz chromium_src-036d87726035ac500ba35ab41fdc9ef6128f0e4f.tar.bz2 |
[new http] Normalize line continuations in response headers.
BUG=1272571
Review URL: http://codereview.chromium.org/458
git-svn-id: svn://svn.chromium.org/chrome/trunk/src@1818 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'net/http/http_util.cc')
-rw-r--r-- | net/http/http_util.cc | 100 |
1 files changed, 82 insertions, 18 deletions
diff --git a/net/http/http_util.cc b/net/http/http_util.cc index ef311dd..7d2bf4a 100644 --- a/net/http/http_util.cc +++ b/net/http/http_util.cc @@ -10,6 +10,7 @@ #include <algorithm> #include "base/logging.h" +#include "base/string_piece.h" #include "base/string_util.h" using std::string; @@ -218,14 +219,18 @@ bool HttpUtil::IsNonCoalescingHeader(string::const_iterator name_begin, return false; } +bool HttpUtil::IsLWS(char c) { + return strchr(HTTP_LWS, c) != NULL; +} + void HttpUtil::TrimLWS(string::const_iterator* begin, string::const_iterator* end) { // leading whitespace - while (*begin < *end && strchr(HTTP_LWS, (*begin)[0])) + while (*begin < *end && IsLWS((*begin)[0])) ++(*begin); // trailing whitespace - while (*begin < *end && strchr(HTTP_LWS, (*end)[-1])) + while (*begin < *end && IsLWS((*end)[-1])) --(*end); } @@ -246,27 +251,79 @@ int HttpUtil::LocateEndOfHeaders(const char* buf, int buf_len) { return -1; } -std::string HttpUtil::AssembleRawHeaders(const char* buf, int buf_len) { +// 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. +static bool IsLineSegmentContinuable(const char* begin, const char* end) { + if (begin == end) + return false; + + const char* colon = std::find(begin, end, ':'); + if (colon == end) + return false; + + const char* name_begin = begin; + const char* name_end = colon; + + // Name can't be empty. + if (name_begin == name_end) + return false; + + // Can't start with LWS (this would imply the segment is a continuation) + if (HttpUtil::IsLWS(*name_begin)) + return false; + + return true; +} + +// Helper used by AssembleRawHeaders, to find the end of the status line. +static const char* FindStatusLineEnd(const char* begin, const char* end) { + size_t i = StringPiece(begin, end - begin).find_first_of("\r\n"); + if (i == StringPiece::npos) + return end; + return begin + i; +} + +std::string HttpUtil::AssembleRawHeaders(const char* input_begin, + int input_len) { std::string raw_headers; + raw_headers.reserve(input_len); - // TODO(darin): - // - Handle header line continuations. - // - Be careful about CRs that appear spuriously mid header line. + const char* input_end = input_begin + input_len; - int line_start = 0; - for (int i = 0; i < buf_len; ++i) { - char c = buf[i]; - if (c == '\r' || c == '\n') { - if (line_start != i) { - // (line_start,i) is a header line. - raw_headers.append(buf + line_start, buf + i); - raw_headers.push_back('\0'); - } - line_start = i + 1; - } + // Copy the status line. + const char* status_line_end = FindStatusLineEnd(input_begin, input_end); + raw_headers.append(input_begin, status_line_end); + + // After the status line, every subsequent line is a header line segment. + // Should a segment start with LWS, it is a continuation of the previous + // line's field-value. + + // TODO(ericroman): is this too permissive? (delimits on [\r\n]+) + CStringTokenizer lines(status_line_end, input_end, "\r\n"); + + // This variable is true when the previous line was continuable. + bool can_append_continuation = false; + + while (lines.GetNext()) { + const char* line_begin = lines.token_begin(); + const char* line_end = lines.token_end(); + + bool is_continuation = can_append_continuation && IsLWS(*line_begin); + + // Terminate the previous line. + if (!is_continuation) + raw_headers.push_back('\0'); + + // Copy the raw data to output. + raw_headers.append(line_begin, line_end); + + // Check if the current line can be continued. + if (!is_continuation) + can_append_continuation = IsLineSegmentContinuable(line_begin, line_end); } - raw_headers.push_back('\0'); + raw_headers.append("\0\0", 2); return raw_headers; } @@ -296,6 +353,13 @@ bool HttpUtil::HeadersIterator::GetNext() { continue; // skip malformed header name_end_ = colon; + + // If the name starts with LWS, it is an invalid line. + // Leading LWS implies a line continuation, and these should have + // already been joined by AssembleRawHeaders(). + if (name_begin_ == name_end_ || IsLWS(*name_begin_)) + continue; + TrimLWS(&name_begin_, &name_end_); if (name_begin_ == name_end_) continue; // skip malformed header |