summaryrefslogtreecommitdiffstats
path: root/net/http/http_util.cc
diff options
context:
space:
mode:
authorericroman@google.com <ericroman@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-09-06 01:00:53 +0000
committerericroman@google.com <ericroman@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2008-09-06 01:00:53 +0000
commit036d87726035ac500ba35ab41fdc9ef6128f0e4f (patch)
tree48f2abffad974fd7599616cd2fa7888f2a5d7fe8 /net/http/http_util.cc
parent9b323e40ae67692745459f68920f5dab61aaaed3 (diff)
downloadchromium_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.cc100
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