Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(852)

Unified Diff: net/http/http_util.cc

Issue 458: [new http] Normalize line continuations in response headers. (Closed) Base URL: svn://chrome-svn/chrome/trunk/src/
Patch Set: '' Created 12 years, 3 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « net/http/http_util.h ('k') | net/http/http_util_unittest.cc » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: net/http/http_util.cc
===================================================================
--- net/http/http_util.cc (revision 1706)
+++ net/http/http_util.cc (working copy)
@@ -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 @@
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 @@
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 @@
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
« no previous file with comments | « net/http/http_util.h ('k') | net/http/http_util_unittest.cc » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698