| 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
|
|
|