| OLD | NEW |
| 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2006-2008 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 // The rules for parsing content-types were borrowed from Firefox: | 5 // The rules for parsing content-types were borrowed from Firefox: |
| 6 // http://lxr.mozilla.org/mozilla/source/netwerk/base/src/nsURLHelper.cpp#834 | 6 // http://lxr.mozilla.org/mozilla/source/netwerk/base/src/nsURLHelper.cpp#834 |
| 7 | 7 |
| 8 #include "net/http/http_util.h" | 8 #include "net/http/http_util.h" |
| 9 | 9 |
| 10 #include <algorithm> | 10 #include <algorithm> |
| 11 | 11 |
| 12 #include "base/logging.h" | 12 #include "base/logging.h" |
| 13 #include "base/string_piece.h" |
| 13 #include "base/string_util.h" | 14 #include "base/string_util.h" |
| 14 | 15 |
| 15 using std::string; | 16 using std::string; |
| 16 | 17 |
| 17 namespace net { | 18 namespace net { |
| 18 | 19 |
| 19 //----------------------------------------------------------------------------- | 20 //----------------------------------------------------------------------------- |
| 20 | 21 |
| 21 // Return the index of the closing quote of the string, if any. | 22 // Return the index of the closing quote of the string, if any. |
| 22 static size_t FindStringEnd(const string& line, size_t start, char delim) { | 23 static size_t FindStringEnd(const string& line, size_t start, char delim) { |
| (...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 211 "retry-after", | 212 "retry-after", |
| 212 "set-cookie" | 213 "set-cookie" |
| 213 }; | 214 }; |
| 214 for (size_t i = 0; i < arraysize(kNonCoalescingHeaders); ++i) { | 215 for (size_t i = 0; i < arraysize(kNonCoalescingHeaders); ++i) { |
| 215 if (LowerCaseEqualsASCII(name_begin, name_end, kNonCoalescingHeaders[i])) | 216 if (LowerCaseEqualsASCII(name_begin, name_end, kNonCoalescingHeaders[i])) |
| 216 return true; | 217 return true; |
| 217 } | 218 } |
| 218 return false; | 219 return false; |
| 219 } | 220 } |
| 220 | 221 |
| 222 bool HttpUtil::IsLWS(char c) { |
| 223 return strchr(HTTP_LWS, c) != NULL; |
| 224 } |
| 225 |
| 221 void HttpUtil::TrimLWS(string::const_iterator* begin, | 226 void HttpUtil::TrimLWS(string::const_iterator* begin, |
| 222 string::const_iterator* end) { | 227 string::const_iterator* end) { |
| 223 // leading whitespace | 228 // leading whitespace |
| 224 while (*begin < *end && strchr(HTTP_LWS, (*begin)[0])) | 229 while (*begin < *end && IsLWS((*begin)[0])) |
| 225 ++(*begin); | 230 ++(*begin); |
| 226 | 231 |
| 227 // trailing whitespace | 232 // trailing whitespace |
| 228 while (*begin < *end && strchr(HTTP_LWS, (*end)[-1])) | 233 while (*begin < *end && IsLWS((*end)[-1])) |
| 229 --(*end); | 234 --(*end); |
| 230 } | 235 } |
| 231 | 236 |
| 232 int HttpUtil::LocateEndOfHeaders(const char* buf, int buf_len) { | 237 int HttpUtil::LocateEndOfHeaders(const char* buf, int buf_len) { |
| 233 bool was_lf = false; | 238 bool was_lf = false; |
| 234 char last_c = '\0'; | 239 char last_c = '\0'; |
| 235 for (int i = 0; i < buf_len; ++i) { | 240 for (int i = 0; i < buf_len; ++i) { |
| 236 char c = buf[i]; | 241 char c = buf[i]; |
| 237 if (c == '\n') { | 242 if (c == '\n') { |
| 238 if (was_lf) | 243 if (was_lf) |
| 239 return i + 1; | 244 return i + 1; |
| 240 was_lf = true; | 245 was_lf = true; |
| 241 } else if (c != '\r' || last_c != '\n') { | 246 } else if (c != '\r' || last_c != '\n') { |
| 242 was_lf = false; | 247 was_lf = false; |
| 243 } | 248 } |
| 244 last_c = c; | 249 last_c = c; |
| 245 } | 250 } |
| 246 return -1; | 251 return -1; |
| 247 } | 252 } |
| 248 | 253 |
| 249 std::string HttpUtil::AssembleRawHeaders(const char* buf, int buf_len) { | 254 // In order for a line to be continuable, it must specify a |
| 255 // non-blank header-name. Line continuations are specifically for |
| 256 // header values -- do not allow headers names to span lines. |
| 257 static bool IsLineSegmentContinuable(const char* begin, const char* end) { |
| 258 if (begin == end) |
| 259 return false; |
| 260 |
| 261 const char* colon = std::find(begin, end, ':'); |
| 262 if (colon == end) |
| 263 return false; |
| 264 |
| 265 const char* name_begin = begin; |
| 266 const char* name_end = colon; |
| 267 |
| 268 // Name can't be empty. |
| 269 if (name_begin == name_end) |
| 270 return false; |
| 271 |
| 272 // Can't start with LWS (this would imply the segment is a continuation) |
| 273 if (HttpUtil::IsLWS(*name_begin)) |
| 274 return false; |
| 275 |
| 276 return true; |
| 277 } |
| 278 |
| 279 // Helper used by AssembleRawHeaders, to find the end of the status line. |
| 280 static const char* FindStatusLineEnd(const char* begin, const char* end) { |
| 281 size_t i = StringPiece(begin, end - begin).find_first_of("\r\n"); |
| 282 if (i == StringPiece::npos) |
| 283 return end; |
| 284 return begin + i; |
| 285 } |
| 286 |
| 287 std::string HttpUtil::AssembleRawHeaders(const char* input_begin, |
| 288 int input_len) { |
| 250 std::string raw_headers; | 289 std::string raw_headers; |
| 290 raw_headers.reserve(input_len); |
| 251 | 291 |
| 252 // TODO(darin): | 292 const char* input_end = input_begin + input_len; |
| 253 // - Handle header line continuations. | |
| 254 // - Be careful about CRs that appear spuriously mid header line. | |
| 255 | 293 |
| 256 int line_start = 0; | 294 // Copy the status line. |
| 257 for (int i = 0; i < buf_len; ++i) { | 295 const char* status_line_end = FindStatusLineEnd(input_begin, input_end); |
| 258 char c = buf[i]; | 296 raw_headers.append(input_begin, status_line_end); |
| 259 if (c == '\r' || c == '\n') { | 297 |
| 260 if (line_start != i) { | 298 // After the status line, every subsequent line is a header line segment. |
| 261 // (line_start,i) is a header line. | 299 // Should a segment start with LWS, it is a continuation of the previous |
| 262 raw_headers.append(buf + line_start, buf + i); | 300 // line's field-value. |
| 263 raw_headers.push_back('\0'); | 301 |
| 264 } | 302 // TODO(ericroman): is this too permissive? (delimits on [\r\n]+) |
| 265 line_start = i + 1; | 303 CStringTokenizer lines(status_line_end, input_end, "\r\n"); |
| 266 } | 304 |
| 305 // This variable is true when the previous line was continuable. |
| 306 bool can_append_continuation = false; |
| 307 |
| 308 while (lines.GetNext()) { |
| 309 const char* line_begin = lines.token_begin(); |
| 310 const char* line_end = lines.token_end(); |
| 311 |
| 312 bool is_continuation = can_append_continuation && IsLWS(*line_begin); |
| 313 |
| 314 // Terminate the previous line. |
| 315 if (!is_continuation) |
| 316 raw_headers.push_back('\0'); |
| 317 |
| 318 // Copy the raw data to output. |
| 319 raw_headers.append(line_begin, line_end); |
| 320 |
| 321 // Check if the current line can be continued. |
| 322 if (!is_continuation) |
| 323 can_append_continuation = IsLineSegmentContinuable(line_begin, line_end); |
| 267 } | 324 } |
| 268 raw_headers.push_back('\0'); | |
| 269 | 325 |
| 326 raw_headers.append("\0\0", 2); |
| 270 return raw_headers; | 327 return raw_headers; |
| 271 } | 328 } |
| 272 | 329 |
| 273 // BNF from section 4.2 of RFC 2616: | 330 // BNF from section 4.2 of RFC 2616: |
| 274 // | 331 // |
| 275 // message-header = field-name ":" [ field-value ] | 332 // message-header = field-name ":" [ field-value ] |
| 276 // field-name = token | 333 // field-name = token |
| 277 // field-value = *( field-content | LWS ) | 334 // field-value = *( field-content | LWS ) |
| 278 // field-content = <the OCTETs making up the field-value | 335 // field-content = <the OCTETs making up the field-value |
| 279 // and consisting of either *TEXT or combinations | 336 // and consisting of either *TEXT or combinations |
| 280 // of token, separators, and quoted-string> | 337 // of token, separators, and quoted-string> |
| 281 // | 338 // |
| 282 | 339 |
| 283 HttpUtil::HeadersIterator::HeadersIterator(string::const_iterator headers_begin, | 340 HttpUtil::HeadersIterator::HeadersIterator(string::const_iterator headers_begin, |
| 284 string::const_iterator headers_end, | 341 string::const_iterator headers_end, |
| 285 const std::string& line_delimiter) | 342 const std::string& line_delimiter) |
| 286 : lines_(headers_begin, headers_end, line_delimiter) { | 343 : lines_(headers_begin, headers_end, line_delimiter) { |
| 287 } | 344 } |
| 288 | 345 |
| 289 bool HttpUtil::HeadersIterator::GetNext() { | 346 bool HttpUtil::HeadersIterator::GetNext() { |
| 290 while (lines_.GetNext()) { | 347 while (lines_.GetNext()) { |
| 291 name_begin_ = lines_.token_begin(); | 348 name_begin_ = lines_.token_begin(); |
| 292 values_end_ = lines_.token_end(); | 349 values_end_ = lines_.token_end(); |
| 293 | 350 |
| 294 string::const_iterator colon = find(name_begin_, values_end_, ':'); | 351 string::const_iterator colon = find(name_begin_, values_end_, ':'); |
| 295 if (colon == values_end_) | 352 if (colon == values_end_) |
| 296 continue; // skip malformed header | 353 continue; // skip malformed header |
| 297 | 354 |
| 298 name_end_ = colon; | 355 name_end_ = colon; |
| 356 |
| 357 // If the name starts with LWS, it is an invalid line. |
| 358 // Leading LWS implies a line continuation, and these should have |
| 359 // already been joined by AssembleRawHeaders(). |
| 360 if (name_begin_ == name_end_ || IsLWS(*name_begin_)) |
| 361 continue; |
| 362 |
| 299 TrimLWS(&name_begin_, &name_end_); | 363 TrimLWS(&name_begin_, &name_end_); |
| 300 if (name_begin_ == name_end_) | 364 if (name_begin_ == name_end_) |
| 301 continue; // skip malformed header | 365 continue; // skip malformed header |
| 302 | 366 |
| 303 values_begin_ = colon + 1; | 367 values_begin_ = colon + 1; |
| 304 TrimLWS(&values_begin_, &values_end_); | 368 TrimLWS(&values_begin_, &values_end_); |
| 305 | 369 |
| 306 // if we got a header name, then we are done. | 370 // if we got a header name, then we are done. |
| 307 return true; | 371 return true; |
| 308 } | 372 } |
| (...skipping 16 matching lines...) Expand all Loading... |
| 325 | 389 |
| 326 // bypass empty values. | 390 // bypass empty values. |
| 327 if (value_begin_ != value_end_) | 391 if (value_begin_ != value_end_) |
| 328 return true; | 392 return true; |
| 329 } | 393 } |
| 330 return false; | 394 return false; |
| 331 } | 395 } |
| 332 | 396 |
| 333 } // namespace net | 397 } // namespace net |
| 334 | 398 |
| OLD | NEW |