| OLD | NEW |
| 1 // Copyright (c) 2012 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2012 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 header parsing were borrowed from Firefox: | 5 // The rules for header parsing were borrowed from Firefox: |
| 6 // http://lxr.mozilla.org/seamonkey/source/netwerk/protocol/http/src/nsHttpRespo
nseHead.cpp | 6 // http://lxr.mozilla.org/seamonkey/source/netwerk/protocol/http/src/nsHttpRespo
nseHead.cpp |
| 7 // The rules for parsing content-types were also borrowed from Firefox: | 7 // The rules for parsing content-types were also borrowed from Firefox: |
| 8 // http://lxr.mozilla.org/mozilla/source/netwerk/base/src/nsURLHelper.cpp#834 | 8 // http://lxr.mozilla.org/mozilla/source/netwerk/base/src/nsURLHelper.cpp#834 |
| 9 | 9 |
| 10 #include "net/http/http_response_headers.h" | 10 #include "net/http/http_response_headers.h" |
| (...skipping 26 matching lines...) Expand all Loading... |
| 37 | 37 |
| 38 namespace net { | 38 namespace net { |
| 39 | 39 |
| 40 //----------------------------------------------------------------------------- | 40 //----------------------------------------------------------------------------- |
| 41 | 41 |
| 42 namespace { | 42 namespace { |
| 43 | 43 |
| 44 // These headers are RFC 2616 hop-by-hop headers; | 44 // These headers are RFC 2616 hop-by-hop headers; |
| 45 // not to be stored by caches. | 45 // not to be stored by caches. |
| 46 const char* const kHopByHopResponseHeaders[] = { | 46 const char* const kHopByHopResponseHeaders[] = { |
| 47 "connection", | 47 "connection", "proxy-connection", "keep-alive", |
| 48 "proxy-connection", | 48 "trailer", "transfer-encoding", "upgrade"}; |
| 49 "keep-alive", | |
| 50 "trailer", | |
| 51 "transfer-encoding", | |
| 52 "upgrade" | |
| 53 }; | |
| 54 | 49 |
| 55 // These headers are challenge response headers; | 50 // These headers are challenge response headers; |
| 56 // not to be stored by caches. | 51 // not to be stored by caches. |
| 57 const char* const kChallengeResponseHeaders[] = { | 52 const char* const kChallengeResponseHeaders[] = {"www-authenticate", |
| 58 "www-authenticate", | 53 "proxy-authenticate"}; |
| 59 "proxy-authenticate" | |
| 60 }; | |
| 61 | 54 |
| 62 // These headers are cookie setting headers; | 55 // These headers are cookie setting headers; |
| 63 // not to be stored by caches or disclosed otherwise. | 56 // not to be stored by caches or disclosed otherwise. |
| 64 const char* const kCookieResponseHeaders[] = { | 57 const char* const kCookieResponseHeaders[] = {"set-cookie", "set-cookie2"}; |
| 65 "set-cookie", | |
| 66 "set-cookie2" | |
| 67 }; | |
| 68 | 58 |
| 69 // By default, do not cache Strict-Transport-Security or Public-Key-Pins. | 59 // By default, do not cache Strict-Transport-Security or Public-Key-Pins. |
| 70 // This avoids erroneously re-processing them on page loads from cache --- | 60 // This avoids erroneously re-processing them on page loads from cache --- |
| 71 // they are defined to be valid only on live and error-free HTTPS | 61 // they are defined to be valid only on live and error-free HTTPS |
| 72 // connections. | 62 // connections. |
| 73 const char* const kSecurityStateHeaders[] = { | 63 const char* const kSecurityStateHeaders[] = {"strict-transport-security", |
| 74 "strict-transport-security", | 64 "public-key-pins"}; |
| 75 "public-key-pins" | |
| 76 }; | |
| 77 | 65 |
| 78 // These response headers are not copied from a 304/206 response to the cached | 66 // These response headers are not copied from a 304/206 response to the cached |
| 79 // response headers. This list is based on Mozilla's nsHttpResponseHead.cpp. | 67 // response headers. This list is based on Mozilla's nsHttpResponseHead.cpp. |
| 80 const char* const kNonUpdatedHeaders[] = { | 68 const char* const kNonUpdatedHeaders[] = { |
| 81 "connection", | 69 "connection", "proxy-connection", "keep-alive", |
| 82 "proxy-connection", | 70 "www-authenticate", "proxy-authenticate", "trailer", |
| 83 "keep-alive", | 71 "transfer-encoding", "upgrade", "etag", |
| 84 "www-authenticate", | 72 "x-frame-options", "x-xss-protection", |
| 85 "proxy-authenticate", | |
| 86 "trailer", | |
| 87 "transfer-encoding", | |
| 88 "upgrade", | |
| 89 "etag", | |
| 90 "x-frame-options", | |
| 91 "x-xss-protection", | |
| 92 }; | 73 }; |
| 93 | 74 |
| 94 // Some header prefixes mean "Don't copy this header from a 304 response.". | 75 // Some header prefixes mean "Don't copy this header from a 304 response.". |
| 95 // Rather than listing all the relevant headers, we can consolidate them into | 76 // Rather than listing all the relevant headers, we can consolidate them into |
| 96 // this list: | 77 // this list: |
| 97 const char* const kNonUpdatedHeaderPrefixes[] = { | 78 const char* const kNonUpdatedHeaderPrefixes[] = {"content-", "x-content-", |
| 98 "content-", | 79 "x-webkit-"}; |
| 99 "x-content-", | |
| 100 "x-webkit-" | |
| 101 }; | |
| 102 | 80 |
| 103 bool ShouldUpdateHeader(const std::string::const_iterator& name_begin, | 81 bool ShouldUpdateHeader(const std::string::const_iterator& name_begin, |
| 104 const std::string::const_iterator& name_end) { | 82 const std::string::const_iterator& name_end) { |
| 105 for (size_t i = 0; i < arraysize(kNonUpdatedHeaders); ++i) { | 83 for (size_t i = 0; i < arraysize(kNonUpdatedHeaders); ++i) { |
| 106 if (LowerCaseEqualsASCII(name_begin, name_end, kNonUpdatedHeaders[i])) | 84 if (LowerCaseEqualsASCII(name_begin, name_end, kNonUpdatedHeaders[i])) |
| 107 return false; | 85 return false; |
| 108 } | 86 } |
| 109 for (size_t i = 0; i < arraysize(kNonUpdatedHeaderPrefixes); ++i) { | 87 for (size_t i = 0; i < arraysize(kNonUpdatedHeaderPrefixes); ++i) { |
| 110 if (StartsWithASCII(std::string(name_begin, name_end), | 88 if (StartsWithASCII(std::string(name_begin, name_end), |
| 111 kNonUpdatedHeaderPrefixes[i], false)) | 89 kNonUpdatedHeaderPrefixes[i], |
| 90 false)) |
| 112 return false; | 91 return false; |
| 113 } | 92 } |
| 114 return true; | 93 return true; |
| 115 } | 94 } |
| 116 | 95 |
| 117 void CheckDoesNotHaveEmbededNulls(const std::string& str) { | 96 void CheckDoesNotHaveEmbededNulls(const std::string& str) { |
| 118 // Care needs to be taken when adding values to the raw headers string to | 97 // Care needs to be taken when adding values to the raw headers string to |
| 119 // make sure it does not contain embeded NULLs. Any embeded '\0' may be | 98 // make sure it does not contain embeded NULLs. Any embeded '\0' may be |
| 120 // understood as line terminators and change how header lines get tokenized. | 99 // understood as line terminators and change how header lines get tokenized. |
| 121 CHECK(str.find('\0') == std::string::npos); | 100 CHECK(str.find('\0') == std::string::npos); |
| (...skipping 23 matching lines...) Expand all Loading... |
| 145 // The most important thing to do with this histogram is find out | 124 // The most important thing to do with this histogram is find out |
| 146 // the existence of unusual HTTP status codes. As it happens | 125 // the existence of unusual HTTP status codes. As it happens |
| 147 // right now, there aren't double-constructions of response headers | 126 // right now, there aren't double-constructions of response headers |
| 148 // using this constructor, so our counts should also be accurate, | 127 // using this constructor, so our counts should also be accurate, |
| 149 // without instantiating the histogram in two places. It is also | 128 // without instantiating the histogram in two places. It is also |
| 150 // important that this histogram not collect data in the other | 129 // important that this histogram not collect data in the other |
| 151 // constructor, which rebuilds an histogram from a pickle, since | 130 // constructor, which rebuilds an histogram from a pickle, since |
| 152 // that would actually create a double call between the original | 131 // that would actually create a double call between the original |
| 153 // HttpResponseHeader that was serialized, and initialization of the | 132 // HttpResponseHeader that was serialized, and initialization of the |
| 154 // new object from that pickle. | 133 // new object from that pickle. |
| 155 UMA_HISTOGRAM_CUSTOM_ENUMERATION("Net.HttpResponseCode", | 134 UMA_HISTOGRAM_CUSTOM_ENUMERATION( |
| 156 HttpUtil::MapStatusCodeForHistogram( | 135 "Net.HttpResponseCode", |
| 157 response_code_), | 136 HttpUtil::MapStatusCodeForHistogram(response_code_), |
| 158 // Note the third argument is only | 137 // Note the third argument is only |
| 159 // evaluated once, see macro | 138 // evaluated once, see macro |
| 160 // definition for details. | 139 // definition for details. |
| 161 HttpUtil::GetStatusCodesForHistogram()); | 140 HttpUtil::GetStatusCodesForHistogram()); |
| 162 } | 141 } |
| 163 | 142 |
| 164 HttpResponseHeaders::HttpResponseHeaders(const Pickle& pickle, | 143 HttpResponseHeaders::HttpResponseHeaders(const Pickle& pickle, |
| 165 PickleIterator* iter) | 144 PickleIterator* iter) |
| 166 : response_code_(-1) { | 145 : response_code_(-1) { |
| 167 std::string raw_input; | 146 std::string raw_input; |
| 168 if (pickle.ReadString(iter, &raw_input)) | 147 if (pickle.ReadString(iter, &raw_input)) |
| 169 Parse(raw_input); | 148 Parse(raw_input); |
| 170 } | 149 } |
| 171 | 150 |
| (...skipping 30 matching lines...) Expand all Loading... |
| 202 // This copies the status line w/ terminator null. | 181 // This copies the status line w/ terminator null. |
| 203 // Note raw_headers_ has embedded nulls instead of \n, | 182 // Note raw_headers_ has embedded nulls instead of \n, |
| 204 // so this just copies the first header line. | 183 // so this just copies the first header line. |
| 205 blob.assign(raw_headers_.c_str(), strlen(raw_headers_.c_str()) + 1); | 184 blob.assign(raw_headers_.c_str(), strlen(raw_headers_.c_str()) + 1); |
| 206 | 185 |
| 207 for (size_t i = 0; i < parsed_.size(); ++i) { | 186 for (size_t i = 0; i < parsed_.size(); ++i) { |
| 208 DCHECK(!parsed_[i].is_continuation()); | 187 DCHECK(!parsed_[i].is_continuation()); |
| 209 | 188 |
| 210 // Locate the start of the next header. | 189 // Locate the start of the next header. |
| 211 size_t k = i; | 190 size_t k = i; |
| 212 while (++k < parsed_.size() && parsed_[k].is_continuation()) {} | 191 while (++k < parsed_.size() && parsed_[k].is_continuation()) { |
| 192 } |
| 213 --k; | 193 --k; |
| 214 | 194 |
| 215 std::string header_name(parsed_[i].name_begin, parsed_[i].name_end); | 195 std::string header_name(parsed_[i].name_begin, parsed_[i].name_end); |
| 216 StringToLowerASCII(&header_name); | 196 StringToLowerASCII(&header_name); |
| 217 | 197 |
| 218 if (filter_headers.find(header_name) == filter_headers.end()) { | 198 if (filter_headers.find(header_name) == filter_headers.end()) { |
| 219 // Make sure there is a null after the value. | 199 // Make sure there is a null after the value. |
| 220 blob.append(parsed_[i].name_begin, parsed_[k].value_end); | 200 blob.append(parsed_[i].name_begin, parsed_[k].value_end); |
| 221 blob.push_back('\0'); | 201 blob.push_back('\0'); |
| 222 } | 202 } |
| (...skipping 19 matching lines...) Expand all Loading... |
| 242 // order should not matter. | 222 // order should not matter. |
| 243 | 223 |
| 244 // Figure out which headers we want to take from new_headers: | 224 // Figure out which headers we want to take from new_headers: |
| 245 for (size_t i = 0; i < new_headers.parsed_.size(); ++i) { | 225 for (size_t i = 0; i < new_headers.parsed_.size(); ++i) { |
| 246 const HeaderList& new_parsed = new_headers.parsed_; | 226 const HeaderList& new_parsed = new_headers.parsed_; |
| 247 | 227 |
| 248 DCHECK(!new_parsed[i].is_continuation()); | 228 DCHECK(!new_parsed[i].is_continuation()); |
| 249 | 229 |
| 250 // Locate the start of the next header. | 230 // Locate the start of the next header. |
| 251 size_t k = i; | 231 size_t k = i; |
| 252 while (++k < new_parsed.size() && new_parsed[k].is_continuation()) {} | 232 while (++k < new_parsed.size() && new_parsed[k].is_continuation()) { |
| 233 } |
| 253 --k; | 234 --k; |
| 254 | 235 |
| 255 const std::string::const_iterator& name_begin = new_parsed[i].name_begin; | 236 const std::string::const_iterator& name_begin = new_parsed[i].name_begin; |
| 256 const std::string::const_iterator& name_end = new_parsed[i].name_end; | 237 const std::string::const_iterator& name_end = new_parsed[i].name_end; |
| 257 if (ShouldUpdateHeader(name_begin, name_end)) { | 238 if (ShouldUpdateHeader(name_begin, name_end)) { |
| 258 std::string name(name_begin, name_end); | 239 std::string name(name_begin, name_end); |
| 259 StringToLowerASCII(&name); | 240 StringToLowerASCII(&name); |
| 260 updated_headers.insert(name); | 241 updated_headers.insert(name); |
| 261 | 242 |
| 262 // Preserve this header line in the merged result, making sure there is | 243 // Preserve this header line in the merged result, making sure there is |
| (...skipping 10 matching lines...) Expand all Loading... |
| 273 } | 254 } |
| 274 | 255 |
| 275 void HttpResponseHeaders::MergeWithHeaders(const std::string& raw_headers, | 256 void HttpResponseHeaders::MergeWithHeaders(const std::string& raw_headers, |
| 276 const HeaderSet& headers_to_remove) { | 257 const HeaderSet& headers_to_remove) { |
| 277 std::string new_raw_headers(raw_headers); | 258 std::string new_raw_headers(raw_headers); |
| 278 for (size_t i = 0; i < parsed_.size(); ++i) { | 259 for (size_t i = 0; i < parsed_.size(); ++i) { |
| 279 DCHECK(!parsed_[i].is_continuation()); | 260 DCHECK(!parsed_[i].is_continuation()); |
| 280 | 261 |
| 281 // Locate the start of the next header. | 262 // Locate the start of the next header. |
| 282 size_t k = i; | 263 size_t k = i; |
| 283 while (++k < parsed_.size() && parsed_[k].is_continuation()) {} | 264 while (++k < parsed_.size() && parsed_[k].is_continuation()) { |
| 265 } |
| 284 --k; | 266 --k; |
| 285 | 267 |
| 286 std::string name(parsed_[i].name_begin, parsed_[i].name_end); | 268 std::string name(parsed_[i].name_begin, parsed_[i].name_end); |
| 287 StringToLowerASCII(&name); | 269 StringToLowerASCII(&name); |
| 288 if (headers_to_remove.find(name) == headers_to_remove.end()) { | 270 if (headers_to_remove.find(name) == headers_to_remove.end()) { |
| 289 // It's ok to preserve this header in the final result. | 271 // It's ok to preserve this header in the final result. |
| 290 new_raw_headers.append(parsed_[i].name_begin, parsed_[k].value_end); | 272 new_raw_headers.append(parsed_[i].name_begin, parsed_[k].value_end); |
| 291 new_raw_headers.push_back('\0'); | 273 new_raw_headers.push_back('\0'); |
| 292 } | 274 } |
| 293 | 275 |
| (...skipping 73 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 367 void HttpResponseHeaders::ReplaceStatusLine(const std::string& new_status) { | 349 void HttpResponseHeaders::ReplaceStatusLine(const std::string& new_status) { |
| 368 CheckDoesNotHaveEmbededNulls(new_status); | 350 CheckDoesNotHaveEmbededNulls(new_status); |
| 369 // Copy up to the null byte. This just copies the status line. | 351 // Copy up to the null byte. This just copies the status line. |
| 370 std::string new_raw_headers(new_status); | 352 std::string new_raw_headers(new_status); |
| 371 new_raw_headers.push_back('\0'); | 353 new_raw_headers.push_back('\0'); |
| 372 | 354 |
| 373 HeaderSet empty_to_remove; | 355 HeaderSet empty_to_remove; |
| 374 MergeWithHeaders(new_raw_headers, empty_to_remove); | 356 MergeWithHeaders(new_raw_headers, empty_to_remove); |
| 375 } | 357 } |
| 376 | 358 |
| 377 void HttpResponseHeaders::UpdateWithNewRange( | 359 void HttpResponseHeaders::UpdateWithNewRange(const HttpByteRange& byte_range, |
| 378 const HttpByteRange& byte_range, | 360 int64 resource_size, |
| 379 int64 resource_size, | 361 bool replace_status_line) { |
| 380 bool replace_status_line) { | |
| 381 DCHECK(byte_range.IsValid()); | 362 DCHECK(byte_range.IsValid()); |
| 382 DCHECK(byte_range.HasFirstBytePosition()); | 363 DCHECK(byte_range.HasFirstBytePosition()); |
| 383 DCHECK(byte_range.HasLastBytePosition()); | 364 DCHECK(byte_range.HasLastBytePosition()); |
| 384 | 365 |
| 385 const char kLengthHeader[] = "Content-Length"; | 366 const char kLengthHeader[] = "Content-Length"; |
| 386 const char kRangeHeader[] = "Content-Range"; | 367 const char kRangeHeader[] = "Content-Range"; |
| 387 | 368 |
| 388 RemoveHeader(kLengthHeader); | 369 RemoveHeader(kLengthHeader); |
| 389 RemoveHeader(kRangeHeader); | 370 RemoveHeader(kRangeHeader); |
| 390 | 371 |
| 391 int64 start = byte_range.first_byte_position(); | 372 int64 start = byte_range.first_byte_position(); |
| 392 int64 end = byte_range.last_byte_position(); | 373 int64 end = byte_range.last_byte_position(); |
| 393 int64 range_len = end - start + 1; | 374 int64 range_len = end - start + 1; |
| 394 | 375 |
| 395 if (replace_status_line) | 376 if (replace_status_line) |
| 396 ReplaceStatusLine("HTTP/1.1 206 Partial Content"); | 377 ReplaceStatusLine("HTTP/1.1 206 Partial Content"); |
| 397 | 378 |
| 398 AddHeader(base::StringPrintf("%s: bytes %" PRId64 "-%" PRId64 "/%" PRId64, | 379 AddHeader(base::StringPrintf("%s: bytes %" PRId64 "-%" PRId64 "/%" PRId64, |
| 399 kRangeHeader, start, end, resource_size)); | 380 kRangeHeader, |
| 381 start, |
| 382 end, |
| 383 resource_size)); |
| 400 AddHeader(base::StringPrintf("%s: %" PRId64, kLengthHeader, range_len)); | 384 AddHeader(base::StringPrintf("%s: %" PRId64, kLengthHeader, range_len)); |
| 401 } | 385 } |
| 402 | 386 |
| 403 void HttpResponseHeaders::Parse(const std::string& raw_input) { | 387 void HttpResponseHeaders::Parse(const std::string& raw_input) { |
| 404 raw_headers_.reserve(raw_input.size()); | 388 raw_headers_.reserve(raw_input.size()); |
| 405 | 389 |
| 406 // ParseStatusLine adds a normalized status line to raw_headers_ | 390 // ParseStatusLine adds a normalized status line to raw_headers_ |
| 407 std::string::const_iterator line_begin = raw_input.begin(); | 391 std::string::const_iterator line_begin = raw_input.begin(); |
| 408 std::string::const_iterator line_end = | 392 std::string::const_iterator line_end = |
| 409 std::find(line_begin, raw_input.end(), '\0'); | 393 std::find(line_begin, raw_input.end(), '\0'); |
| 410 // has_headers = true, if there is any data following the status line. | 394 // has_headers = true, if there is any data following the status line. |
| 411 // Used by ParseStatusLine() to decide if a HTTP/0.9 is really a HTTP/1.0. | 395 // Used by ParseStatusLine() to decide if a HTTP/0.9 is really a HTTP/1.0. |
| 412 bool has_headers = (line_end != raw_input.end() && | 396 bool has_headers = |
| 413 (line_end + 1) != raw_input.end() && | 397 (line_end != raw_input.end() && (line_end + 1) != raw_input.end() && |
| 414 *(line_end + 1) != '\0'); | 398 *(line_end + 1) != '\0'); |
| 415 ParseStatusLine(line_begin, line_end, has_headers); | 399 ParseStatusLine(line_begin, line_end, has_headers); |
| 416 raw_headers_.push_back('\0'); // Terminate status line with a null. | 400 raw_headers_.push_back('\0'); // Terminate status line with a null. |
| 417 | 401 |
| 418 if (line_end == raw_input.end()) { | 402 if (line_end == raw_input.end()) { |
| 419 raw_headers_.push_back('\0'); // Ensure the headers end with a double null. | 403 raw_headers_.push_back('\0'); // Ensure the headers end with a double null. |
| 420 | 404 |
| 421 DCHECK_EQ('\0', raw_headers_[raw_headers_.size() - 2]); | 405 DCHECK_EQ('\0', raw_headers_[raw_headers_.size() - 2]); |
| 422 DCHECK_EQ('\0', raw_headers_[raw_headers_.size() - 1]); | 406 DCHECK_EQ('\0', raw_headers_[raw_headers_.size() - 1]); |
| 423 return; | 407 return; |
| 424 } | 408 } |
| 425 | 409 |
| 426 // Including a terminating null byte. | 410 // Including a terminating null byte. |
| 427 size_t status_line_len = raw_headers_.size(); | 411 size_t status_line_len = raw_headers_.size(); |
| 428 | 412 |
| 429 // Now, we add the rest of the raw headers to raw_headers_, and begin parsing | 413 // Now, we add the rest of the raw headers to raw_headers_, and begin parsing |
| 430 // it (to populate our parsed_ vector). | 414 // it (to populate our parsed_ vector). |
| 431 raw_headers_.append(line_end + 1, raw_input.end()); | 415 raw_headers_.append(line_end + 1, raw_input.end()); |
| 432 | 416 |
| 433 // Ensure the headers end with a double null. | 417 // Ensure the headers end with a double null. |
| 434 while (raw_headers_.size() < 2 || | 418 while (raw_headers_.size() < 2 || |
| 435 raw_headers_[raw_headers_.size() - 2] != '\0' || | 419 raw_headers_[raw_headers_.size() - 2] != '\0' || |
| 436 raw_headers_[raw_headers_.size() - 1] != '\0') { | 420 raw_headers_[raw_headers_.size() - 1] != '\0') { |
| 437 raw_headers_.push_back('\0'); | 421 raw_headers_.push_back('\0'); |
| 438 } | 422 } |
| 439 | 423 |
| 440 // Adjust to point at the null byte following the status line | 424 // Adjust to point at the null byte following the status line |
| 441 line_end = raw_headers_.begin() + status_line_len - 1; | 425 line_end = raw_headers_.begin() + status_line_len - 1; |
| 442 | 426 |
| 443 HttpUtil::HeadersIterator headers(line_end + 1, raw_headers_.end(), | 427 HttpUtil::HeadersIterator headers( |
| 444 std::string(1, '\0')); | 428 line_end + 1, raw_headers_.end(), std::string(1, '\0')); |
| 445 while (headers.GetNext()) { | 429 while (headers.GetNext()) { |
| 446 AddHeader(headers.name_begin(), | 430 AddHeader(headers.name_begin(), |
| 447 headers.name_end(), | 431 headers.name_end(), |
| 448 headers.values_begin(), | 432 headers.values_begin(), |
| 449 headers.values_end()); | 433 headers.values_end()); |
| 450 } | 434 } |
| 451 | 435 |
| 452 DCHECK_EQ('\0', raw_headers_[raw_headers_.size() - 2]); | 436 DCHECK_EQ('\0', raw_headers_[raw_headers_.size() - 2]); |
| 453 DCHECK_EQ('\0', raw_headers_[raw_headers_.size() - 1]); | 437 DCHECK_EQ('\0', raw_headers_[raw_headers_.size() - 1]); |
| 454 } | 438 } |
| (...skipping 21 matching lines...) Expand all Loading... |
| 476 std::vector<std::string> headers; | 460 std::vector<std::string> headers; |
| 477 | 461 |
| 478 for (size_t i = 0; i < parsed_.size(); ++i) { | 462 for (size_t i = 0; i < parsed_.size(); ++i) { |
| 479 DCHECK(!parsed_[i].is_continuation()); | 463 DCHECK(!parsed_[i].is_continuation()); |
| 480 | 464 |
| 481 std::string name(parsed_[i].name_begin, parsed_[i].name_end); | 465 std::string name(parsed_[i].name_begin, parsed_[i].name_end); |
| 482 std::string lower_name = StringToLowerASCII(name); | 466 std::string lower_name = StringToLowerASCII(name); |
| 483 | 467 |
| 484 iter = headers_map.find(lower_name); | 468 iter = headers_map.find(lower_name); |
| 485 if (iter == headers_map.end()) { | 469 if (iter == headers_map.end()) { |
| 486 iter = headers_map.insert( | 470 iter = headers_map.insert(HeadersMap::value_type(lower_name, |
| 487 HeadersMap::value_type(lower_name, headers.size())).first; | 471 headers.size())).first; |
| 488 headers.push_back(name + ": "); | 472 headers.push_back(name + ": "); |
| 489 } else { | 473 } else { |
| 490 headers[iter->second].append(", "); | 474 headers[iter->second].append(", "); |
| 491 } | 475 } |
| 492 | 476 |
| 493 std::string::const_iterator value_begin = parsed_[i].value_begin; | 477 std::string::const_iterator value_begin = parsed_[i].value_begin; |
| 494 std::string::const_iterator value_end = parsed_[i].value_end; | 478 std::string::const_iterator value_end = parsed_[i].value_end; |
| 495 while (++i < parsed_.size() && parsed_[i].is_continuation()) | 479 while (++i < parsed_.size() && parsed_[i].is_continuation()) |
| 496 value_end = parsed_[i].value_end; | 480 value_end = parsed_[i].value_end; |
| 497 --i; | 481 --i; |
| (...skipping 103 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 601 } | 585 } |
| 602 | 586 |
| 603 bool HttpResponseHeaders::HasHeaderValue(const base::StringPiece& name, | 587 bool HttpResponseHeaders::HasHeaderValue(const base::StringPiece& name, |
| 604 const base::StringPiece& value) const { | 588 const base::StringPiece& value) const { |
| 605 // The value has to be an exact match. This is important since | 589 // The value has to be an exact match. This is important since |
| 606 // 'cache-control: no-cache' != 'cache-control: no-cache="foo"' | 590 // 'cache-control: no-cache' != 'cache-control: no-cache="foo"' |
| 607 void* iter = NULL; | 591 void* iter = NULL; |
| 608 std::string temp; | 592 std::string temp; |
| 609 while (EnumerateHeader(&iter, name, &temp)) { | 593 while (EnumerateHeader(&iter, name, &temp)) { |
| 610 if (value.size() == temp.size() && | 594 if (value.size() == temp.size() && |
| 611 std::equal(temp.begin(), temp.end(), value.begin(), | 595 std::equal(temp.begin(), |
| 596 temp.end(), |
| 597 value.begin(), |
| 612 base::CaseInsensitiveCompare<char>())) | 598 base::CaseInsensitiveCompare<char>())) |
| 613 return true; | 599 return true; |
| 614 } | 600 } |
| 615 return false; | 601 return false; |
| 616 } | 602 } |
| 617 | 603 |
| 618 bool HttpResponseHeaders::HasHeader(const base::StringPiece& name) const { | 604 bool HttpResponseHeaders::HasHeader(const base::StringPiece& name) const { |
| 619 return FindHeader(0, name) != std::string::npos; | 605 return FindHeader(0, name) != std::string::npos; |
| 620 } | 606 } |
| 621 | 607 |
| (...skipping 26 matching lines...) Expand all Loading... |
| 648 DVLOG(1) << "missing version"; | 634 DVLOG(1) << "missing version"; |
| 649 return HttpVersion(); | 635 return HttpVersion(); |
| 650 } | 636 } |
| 651 | 637 |
| 652 std::string::const_iterator dot = std::find(p, line_end, '.'); | 638 std::string::const_iterator dot = std::find(p, line_end, '.'); |
| 653 if (dot == line_end) { | 639 if (dot == line_end) { |
| 654 DVLOG(1) << "malformed version"; | 640 DVLOG(1) << "malformed version"; |
| 655 return HttpVersion(); | 641 return HttpVersion(); |
| 656 } | 642 } |
| 657 | 643 |
| 658 ++p; // from / to first digit. | 644 ++p; // from / to first digit. |
| 659 ++dot; // from . to second digit. | 645 ++dot; // from . to second digit. |
| 660 | 646 |
| 661 if (!(*p >= '0' && *p <= '9' && *dot >= '0' && *dot <= '9')) { | 647 if (!(*p >= '0' && *p <= '9' && *dot >= '0' && *dot <= '9')) { |
| 662 DVLOG(1) << "malformed version number"; | 648 DVLOG(1) << "malformed version number"; |
| 663 return HttpVersion(); | 649 return HttpVersion(); |
| 664 } | 650 } |
| 665 | 651 |
| 666 uint16 major = *p - '0'; | 652 uint16 major = *p - '0'; |
| 667 uint16 minor = *dot - '0'; | 653 uint16 minor = *dot - '0'; |
| 668 | 654 |
| (...skipping 74 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 743 } | 729 } |
| 744 | 730 |
| 745 size_t HttpResponseHeaders::FindHeader(size_t from, | 731 size_t HttpResponseHeaders::FindHeader(size_t from, |
| 746 const base::StringPiece& search) const { | 732 const base::StringPiece& search) const { |
| 747 for (size_t i = from; i < parsed_.size(); ++i) { | 733 for (size_t i = from; i < parsed_.size(); ++i) { |
| 748 if (parsed_[i].is_continuation()) | 734 if (parsed_[i].is_continuation()) |
| 749 continue; | 735 continue; |
| 750 const std::string::const_iterator& name_begin = parsed_[i].name_begin; | 736 const std::string::const_iterator& name_begin = parsed_[i].name_begin; |
| 751 const std::string::const_iterator& name_end = parsed_[i].name_end; | 737 const std::string::const_iterator& name_end = parsed_[i].name_end; |
| 752 if (static_cast<size_t>(name_end - name_begin) == search.size() && | 738 if (static_cast<size_t>(name_end - name_begin) == search.size() && |
| 753 std::equal(name_begin, name_end, search.begin(), | 739 std::equal(name_begin, |
| 740 name_end, |
| 741 search.begin(), |
| 754 base::CaseInsensitiveCompare<char>())) | 742 base::CaseInsensitiveCompare<char>())) |
| 755 return i; | 743 return i; |
| 756 } | 744 } |
| 757 | 745 |
| 758 return std::string::npos; | 746 return std::string::npos; |
| 759 } | 747 } |
| 760 | 748 |
| 761 void HttpResponseHeaders::AddHeader(std::string::const_iterator name_begin, | 749 void HttpResponseHeaders::AddHeader(std::string::const_iterator name_begin, |
| 762 std::string::const_iterator name_end, | 750 std::string::const_iterator name_end, |
| 763 std::string::const_iterator values_begin, | 751 std::string::const_iterator values_begin, |
| (...skipping 35 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 799 std::string value; | 787 std::string value; |
| 800 void* iter = NULL; | 788 void* iter = NULL; |
| 801 while (EnumerateHeader(&iter, kCacheControl, &value)) { | 789 while (EnumerateHeader(&iter, kCacheControl, &value)) { |
| 802 // If the value is smaller than the prefix and a terminal quote, skip | 790 // If the value is smaller than the prefix and a terminal quote, skip |
| 803 // it. | 791 // it. |
| 804 if (value.size() <= kPrefixLen || | 792 if (value.size() <= kPrefixLen || |
| 805 value.compare(0, kPrefixLen, kPrefix) != 0) { | 793 value.compare(0, kPrefixLen, kPrefix) != 0) { |
| 806 continue; | 794 continue; |
| 807 } | 795 } |
| 808 // if it doesn't end with a quote, then treat as malformed | 796 // if it doesn't end with a quote, then treat as malformed |
| 809 if (value[value.size()-1] != '\"') | 797 if (value[value.size() - 1] != '\"') |
| 810 continue; | 798 continue; |
| 811 | 799 |
| 812 // process the value as a comma-separated list of items. Each | 800 // process the value as a comma-separated list of items. Each |
| 813 // item can be wrapped by linear white space. | 801 // item can be wrapped by linear white space. |
| 814 std::string::const_iterator item = value.begin() + kPrefixLen; | 802 std::string::const_iterator item = value.begin() + kPrefixLen; |
| 815 std::string::const_iterator end = value.end() - 1; | 803 std::string::const_iterator end = value.end() - 1; |
| 816 while (item != end) { | 804 while (item != end) { |
| 817 // Find the comma to compute the length of the current item, | 805 // Find the comma to compute the length of the current item, |
| 818 // and the position of the next one. | 806 // and the position of the next one. |
| 819 std::string::const_iterator item_next = std::find(item, end, ','); | 807 std::string::const_iterator item_next = std::find(item, end, ','); |
| (...skipping 92 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 912 std::string(parsed_[i].value_begin, parsed_[i].value_end)); | 900 std::string(parsed_[i].value_begin, parsed_[i].value_end)); |
| 913 } | 901 } |
| 914 | 902 |
| 915 return true; | 903 return true; |
| 916 } | 904 } |
| 917 | 905 |
| 918 // static | 906 // static |
| 919 bool HttpResponseHeaders::IsRedirectResponseCode(int response_code) { | 907 bool HttpResponseHeaders::IsRedirectResponseCode(int response_code) { |
| 920 // Users probably want to see 300 (multiple choice) pages, so we don't count | 908 // Users probably want to see 300 (multiple choice) pages, so we don't count |
| 921 // them as redirects that need to be followed. | 909 // them as redirects that need to be followed. |
| 922 return (response_code == 301 || | 910 return (response_code == 301 || response_code == 302 || |
| 923 response_code == 302 || | 911 response_code == 303 || response_code == 307 || response_code == 308); |
| 924 response_code == 303 || | |
| 925 response_code == 307 || | |
| 926 response_code == 308); | |
| 927 } | 912 } |
| 928 | 913 |
| 929 // From RFC 2616 section 13.2.4: | 914 // From RFC 2616 section 13.2.4: |
| 930 // | 915 // |
| 931 // The calculation to determine if a response has expired is quite simple: | 916 // The calculation to determine if a response has expired is quite simple: |
| 932 // | 917 // |
| 933 // response_is_fresh = (freshness_lifetime > current_age) | 918 // response_is_fresh = (freshness_lifetime > current_age) |
| 934 // | 919 // |
| 935 // Of course, there are other factors that can force a response to always be | 920 // Of course, there are other factors that can force a response to always be |
| 936 // validated or re-fetched. | 921 // validated or re-fetched. |
| 937 // | 922 // |
| 938 bool HttpResponseHeaders::RequiresValidation(const Time& request_time, | 923 bool HttpResponseHeaders::RequiresValidation(const Time& request_time, |
| 939 const Time& response_time, | 924 const Time& response_time, |
| 940 const Time& current_time) const { | 925 const Time& current_time) const { |
| 941 TimeDelta lifetime = | 926 TimeDelta lifetime = GetFreshnessLifetime(response_time); |
| 942 GetFreshnessLifetime(response_time); | |
| 943 if (lifetime == TimeDelta()) | 927 if (lifetime == TimeDelta()) |
| 944 return true; | 928 return true; |
| 945 | 929 |
| 946 return lifetime <= GetCurrentAge(request_time, response_time, current_time); | 930 return lifetime <= GetCurrentAge(request_time, response_time, current_time); |
| 947 } | 931 } |
| 948 | 932 |
| 949 // From RFC 2616 section 13.2.4: | 933 // From RFC 2616 section 13.2.4: |
| 950 // | 934 // |
| 951 // The max-age directive takes priority over Expires, so if max-age is present | 935 // The max-age directive takes priority over Expires, so if max-age is present |
| 952 // in a response, the calculation is simply: | 936 // in a response, the calculation is simply: |
| (...skipping 15 matching lines...) Expand all Loading... |
| 968 // | 952 // |
| 969 TimeDelta HttpResponseHeaders::GetFreshnessLifetime( | 953 TimeDelta HttpResponseHeaders::GetFreshnessLifetime( |
| 970 const Time& response_time) const { | 954 const Time& response_time) const { |
| 971 // Check for headers that force a response to never be fresh. For backwards | 955 // Check for headers that force a response to never be fresh. For backwards |
| 972 // compat, we treat "Pragma: no-cache" as a synonym for "Cache-Control: | 956 // compat, we treat "Pragma: no-cache" as a synonym for "Cache-Control: |
| 973 // no-cache" even though RFC 2616 does not specify it. | 957 // no-cache" even though RFC 2616 does not specify it. |
| 974 if (HasHeaderValue("cache-control", "no-cache") || | 958 if (HasHeaderValue("cache-control", "no-cache") || |
| 975 HasHeaderValue("cache-control", "no-store") || | 959 HasHeaderValue("cache-control", "no-store") || |
| 976 HasHeaderValue("pragma", "no-cache") || | 960 HasHeaderValue("pragma", "no-cache") || |
| 977 HasHeaderValue("vary", "*")) // see RFC 2616 section 13.6 | 961 HasHeaderValue("vary", "*")) // see RFC 2616 section 13.6 |
| 978 return TimeDelta(); // not fresh | 962 return TimeDelta(); // not fresh |
| 979 | 963 |
| 980 // NOTE: "Cache-Control: max-age" overrides Expires, so we only check the | 964 // NOTE: "Cache-Control: max-age" overrides Expires, so we only check the |
| 981 // Expires header after checking for max-age in GetFreshnessLifetime. This | 965 // Expires header after checking for max-age in GetFreshnessLifetime. This |
| 982 // is important since "Expires: <date in the past>" means not fresh, but | 966 // is important since "Expires: <date in the past>" means not fresh, but |
| 983 // it should not trump a max-age value. | 967 // it should not trump a max-age value. |
| 984 | 968 |
| 985 TimeDelta max_age_value; | 969 TimeDelta max_age_value; |
| 986 if (GetMaxAgeValue(&max_age_value)) | 970 if (GetMaxAgeValue(&max_age_value)) |
| 987 return max_age_value; | 971 return max_age_value; |
| 988 | 972 |
| (...skipping 110 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1099 bool HttpResponseHeaders::GetMaxAgeValue(TimeDelta* result) const { | 1083 bool HttpResponseHeaders::GetMaxAgeValue(TimeDelta* result) const { |
| 1100 std::string name = "cache-control"; | 1084 std::string name = "cache-control"; |
| 1101 std::string value; | 1085 std::string value; |
| 1102 | 1086 |
| 1103 const char kMaxAgePrefix[] = "max-age="; | 1087 const char kMaxAgePrefix[] = "max-age="; |
| 1104 const size_t kMaxAgePrefixLen = arraysize(kMaxAgePrefix) - 1; | 1088 const size_t kMaxAgePrefixLen = arraysize(kMaxAgePrefix) - 1; |
| 1105 | 1089 |
| 1106 void* iter = NULL; | 1090 void* iter = NULL; |
| 1107 while (EnumerateHeader(&iter, name, &value)) { | 1091 while (EnumerateHeader(&iter, name, &value)) { |
| 1108 if (value.size() > kMaxAgePrefixLen) { | 1092 if (value.size() > kMaxAgePrefixLen) { |
| 1109 if (LowerCaseEqualsASCII(value.begin(), | 1093 if (LowerCaseEqualsASCII( |
| 1110 value.begin() + kMaxAgePrefixLen, | 1094 value.begin(), value.begin() + kMaxAgePrefixLen, kMaxAgePrefix)) { |
| 1111 kMaxAgePrefix)) { | |
| 1112 int64 seconds; | 1095 int64 seconds; |
| 1113 base::StringToInt64(StringPiece(value.begin() + kMaxAgePrefixLen, | 1096 base::StringToInt64( |
| 1114 value.end()), | 1097 StringPiece(value.begin() + kMaxAgePrefixLen, value.end()), |
| 1115 &seconds); | 1098 &seconds); |
| 1116 *result = TimeDelta::FromSeconds(seconds); | 1099 *result = TimeDelta::FromSeconds(seconds); |
| 1117 return true; | 1100 return true; |
| 1118 } | 1101 } |
| 1119 } | 1102 } |
| 1120 } | 1103 } |
| 1121 | 1104 |
| 1122 return false; | 1105 return false; |
| 1123 } | 1106 } |
| 1124 | 1107 |
| 1125 bool HttpResponseHeaders::GetAgeValue(TimeDelta* result) const { | 1108 bool HttpResponseHeaders::GetAgeValue(TimeDelta* result) const { |
| (...skipping 63 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1189 return keep_alive; | 1172 return keep_alive; |
| 1190 } | 1173 } |
| 1191 | 1174 |
| 1192 bool HttpResponseHeaders::HasStrongValidators() const { | 1175 bool HttpResponseHeaders::HasStrongValidators() const { |
| 1193 std::string etag_header; | 1176 std::string etag_header; |
| 1194 EnumerateHeader(NULL, "etag", &etag_header); | 1177 EnumerateHeader(NULL, "etag", &etag_header); |
| 1195 std::string last_modified_header; | 1178 std::string last_modified_header; |
| 1196 EnumerateHeader(NULL, "Last-Modified", &last_modified_header); | 1179 EnumerateHeader(NULL, "Last-Modified", &last_modified_header); |
| 1197 std::string date_header; | 1180 std::string date_header; |
| 1198 EnumerateHeader(NULL, "Date", &date_header); | 1181 EnumerateHeader(NULL, "Date", &date_header); |
| 1199 return HttpUtil::HasStrongValidators(GetHttpVersion(), | 1182 return HttpUtil::HasStrongValidators( |
| 1200 etag_header, | 1183 GetHttpVersion(), etag_header, last_modified_header, date_header); |
| 1201 last_modified_header, | |
| 1202 date_header); | |
| 1203 } | 1184 } |
| 1204 | 1185 |
| 1205 // From RFC 2616: | 1186 // From RFC 2616: |
| 1206 // Content-Length = "Content-Length" ":" 1*DIGIT | 1187 // Content-Length = "Content-Length" ":" 1*DIGIT |
| 1207 int64 HttpResponseHeaders::GetContentLength() const { | 1188 int64 HttpResponseHeaders::GetContentLength() const { |
| 1208 return GetInt64HeaderValue("content-length"); | 1189 return GetInt64HeaderValue("content-length"); |
| 1209 } | 1190 } |
| 1210 | 1191 |
| 1211 int64 HttpResponseHeaders::GetInt64HeaderValue( | 1192 int64 HttpResponseHeaders::GetInt64HeaderValue( |
| 1212 const std::string& header) const { | 1193 const std::string& header) const { |
| (...skipping 38 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1251 size_t space_position = content_range_spec.find(' '); | 1232 size_t space_position = content_range_spec.find(' '); |
| 1252 if (space_position == std::string::npos) | 1233 if (space_position == std::string::npos) |
| 1253 return false; | 1234 return false; |
| 1254 | 1235 |
| 1255 // Invalid header if it doesn't contain "bytes-unit". | 1236 // Invalid header if it doesn't contain "bytes-unit". |
| 1256 std::string::const_iterator content_range_spec_begin = | 1237 std::string::const_iterator content_range_spec_begin = |
| 1257 content_range_spec.begin(); | 1238 content_range_spec.begin(); |
| 1258 std::string::const_iterator content_range_spec_end = | 1239 std::string::const_iterator content_range_spec_end = |
| 1259 content_range_spec.begin() + space_position; | 1240 content_range_spec.begin() + space_position; |
| 1260 HttpUtil::TrimLWS(&content_range_spec_begin, &content_range_spec_end); | 1241 HttpUtil::TrimLWS(&content_range_spec_begin, &content_range_spec_end); |
| 1261 if (!LowerCaseEqualsASCII(content_range_spec_begin, | 1242 if (!LowerCaseEqualsASCII( |
| 1262 content_range_spec_end, | 1243 content_range_spec_begin, content_range_spec_end, "bytes")) { |
| 1263 "bytes")) { | |
| 1264 return false; | 1244 return false; |
| 1265 } | 1245 } |
| 1266 | 1246 |
| 1267 size_t slash_position = content_range_spec.find('/', space_position + 1); | 1247 size_t slash_position = content_range_spec.find('/', space_position + 1); |
| 1268 if (slash_position == std::string::npos) | 1248 if (slash_position == std::string::npos) |
| 1269 return false; | 1249 return false; |
| 1270 | 1250 |
| 1271 // Obtain the part behind the space and before slash. | 1251 // Obtain the part behind the space and before slash. |
| 1272 std::string::const_iterator byte_range_resp_spec_begin = | 1252 std::string::const_iterator byte_range_resp_spec_begin = |
| 1273 content_range_spec.begin() + space_position + 1; | 1253 content_range_spec.begin() + space_position + 1; |
| 1274 std::string::const_iterator byte_range_resp_spec_end = | 1254 std::string::const_iterator byte_range_resp_spec_end = |
| 1275 content_range_spec.begin() + slash_position; | 1255 content_range_spec.begin() + slash_position; |
| 1276 HttpUtil::TrimLWS(&byte_range_resp_spec_begin, &byte_range_resp_spec_end); | 1256 HttpUtil::TrimLWS(&byte_range_resp_spec_begin, &byte_range_resp_spec_end); |
| 1277 | 1257 |
| 1278 // Parse the byte-range-resp-spec part. | 1258 // Parse the byte-range-resp-spec part. |
| 1279 std::string byte_range_resp_spec(byte_range_resp_spec_begin, | 1259 std::string byte_range_resp_spec(byte_range_resp_spec_begin, |
| 1280 byte_range_resp_spec_end); | 1260 byte_range_resp_spec_end); |
| 1281 // If byte-range-resp-spec != "*". | 1261 // If byte-range-resp-spec != "*". |
| 1282 if (!LowerCaseEqualsASCII(byte_range_resp_spec, "*")) { | 1262 if (!LowerCaseEqualsASCII(byte_range_resp_spec, "*")) { |
| 1283 size_t minus_position = byte_range_resp_spec.find('-'); | 1263 size_t minus_position = byte_range_resp_spec.find('-'); |
| 1284 if (minus_position != std::string::npos) { | 1264 if (minus_position != std::string::npos) { |
| 1285 // Obtain first-byte-pos. | 1265 // Obtain first-byte-pos. |
| 1286 std::string::const_iterator first_byte_pos_begin = | 1266 std::string::const_iterator first_byte_pos_begin = |
| 1287 byte_range_resp_spec.begin(); | 1267 byte_range_resp_spec.begin(); |
| 1288 std::string::const_iterator first_byte_pos_end = | 1268 std::string::const_iterator first_byte_pos_end = |
| 1289 byte_range_resp_spec.begin() + minus_position; | 1269 byte_range_resp_spec.begin() + minus_position; |
| 1290 HttpUtil::TrimLWS(&first_byte_pos_begin, &first_byte_pos_end); | 1270 HttpUtil::TrimLWS(&first_byte_pos_begin, &first_byte_pos_end); |
| 1291 | 1271 |
| 1292 bool ok = base::StringToInt64(StringPiece(first_byte_pos_begin, | 1272 bool ok = base::StringToInt64( |
| 1293 first_byte_pos_end), | 1273 StringPiece(first_byte_pos_begin, first_byte_pos_end), |
| 1294 first_byte_position); | 1274 first_byte_position); |
| 1295 | 1275 |
| 1296 // Obtain last-byte-pos. | 1276 // Obtain last-byte-pos. |
| 1297 std::string::const_iterator last_byte_pos_begin = | 1277 std::string::const_iterator last_byte_pos_begin = |
| 1298 byte_range_resp_spec.begin() + minus_position + 1; | 1278 byte_range_resp_spec.begin() + minus_position + 1; |
| 1299 std::string::const_iterator last_byte_pos_end = | 1279 std::string::const_iterator last_byte_pos_end = |
| 1300 byte_range_resp_spec.end(); | 1280 byte_range_resp_spec.end(); |
| 1301 HttpUtil::TrimLWS(&last_byte_pos_begin, &last_byte_pos_end); | 1281 HttpUtil::TrimLWS(&last_byte_pos_begin, &last_byte_pos_end); |
| 1302 | 1282 |
| 1303 ok &= base::StringToInt64(StringPiece(last_byte_pos_begin, | 1283 ok &= base::StringToInt64( |
| 1304 last_byte_pos_end), | 1284 StringPiece(last_byte_pos_begin, last_byte_pos_end), |
| 1305 last_byte_position); | 1285 last_byte_position); |
| 1306 if (!ok) { | 1286 if (!ok) { |
| 1307 *first_byte_position = *last_byte_position = -1; | 1287 *first_byte_position = *last_byte_position = -1; |
| 1308 return false; | 1288 return false; |
| 1309 } | 1289 } |
| 1310 if (*first_byte_position < 0 || *last_byte_position < 0 || | 1290 if (*first_byte_position < 0 || *last_byte_position < 0 || |
| 1311 *first_byte_position > *last_byte_position) | 1291 *first_byte_position > *last_byte_position) |
| 1312 return false; | 1292 return false; |
| 1313 } else { | 1293 } else { |
| 1314 return false; | 1294 return false; |
| 1315 } | 1295 } |
| 1316 } | 1296 } |
| 1317 | 1297 |
| 1318 // Parse the instance-length part. | 1298 // Parse the instance-length part. |
| 1319 // If instance-length == "*". | 1299 // If instance-length == "*". |
| 1320 std::string::const_iterator instance_length_begin = | 1300 std::string::const_iterator instance_length_begin = |
| 1321 content_range_spec.begin() + slash_position + 1; | 1301 content_range_spec.begin() + slash_position + 1; |
| 1322 std::string::const_iterator instance_length_end = | 1302 std::string::const_iterator instance_length_end = content_range_spec.end(); |
| 1323 content_range_spec.end(); | |
| 1324 HttpUtil::TrimLWS(&instance_length_begin, &instance_length_end); | 1303 HttpUtil::TrimLWS(&instance_length_begin, &instance_length_end); |
| 1325 | 1304 |
| 1326 if (LowerCaseEqualsASCII(instance_length_begin, instance_length_end, "*")) { | 1305 if (LowerCaseEqualsASCII(instance_length_begin, instance_length_end, "*")) { |
| 1327 return false; | 1306 return false; |
| 1328 } else if (!base::StringToInt64(StringPiece(instance_length_begin, | 1307 } else if (!base::StringToInt64( |
| 1329 instance_length_end), | 1308 StringPiece(instance_length_begin, instance_length_end), |
| 1330 instance_length)) { | 1309 instance_length)) { |
| 1331 *instance_length = -1; | 1310 *instance_length = -1; |
| 1332 return false; | 1311 return false; |
| 1333 } | 1312 } |
| 1334 | 1313 |
| 1335 // We have all the values; let's verify that they make sense for a 206 | 1314 // We have all the values; let's verify that they make sense for a 206 |
| 1336 // response. | 1315 // response. |
| 1337 if (*first_byte_position < 0 || *last_byte_position < 0 || | 1316 if (*first_byte_position < 0 || *last_byte_position < 0 || |
| 1338 *instance_length < 0 || *instance_length - 1 < *last_byte_position) | 1317 *instance_length < 0 || *instance_length - 1 < *last_byte_position) |
| 1339 return false; | 1318 return false; |
| 1340 | 1319 |
| 1341 return true; | 1320 return true; |
| 1342 } | 1321 } |
| 1343 | 1322 |
| 1344 base::Value* HttpResponseHeaders::NetLogCallback( | 1323 base::Value* HttpResponseHeaders::NetLogCallback( |
| 1345 NetLog::LogLevel log_level) const { | 1324 NetLog::LogLevel log_level) const { |
| 1346 base::DictionaryValue* dict = new base::DictionaryValue(); | 1325 base::DictionaryValue* dict = new base::DictionaryValue(); |
| 1347 base::ListValue* headers = new base::ListValue(); | 1326 base::ListValue* headers = new base::ListValue(); |
| 1348 headers->Append(new base::StringValue(GetStatusLine())); | 1327 headers->Append(new base::StringValue(GetStatusLine())); |
| 1349 void* iterator = NULL; | 1328 void* iterator = NULL; |
| 1350 std::string name; | 1329 std::string name; |
| 1351 std::string value; | 1330 std::string value; |
| 1352 while (EnumerateHeaderLines(&iterator, &name, &value)) { | 1331 while (EnumerateHeaderLines(&iterator, &name, &value)) { |
| 1353 std::string log_value = ElideHeaderValueForNetLog(log_level, name, value); | 1332 std::string log_value = ElideHeaderValueForNetLog(log_level, name, value); |
| 1354 headers->Append( | 1333 headers->Append(new base::StringValue( |
| 1355 new base::StringValue( | 1334 base::StringPrintf("%s: %s", name.c_str(), log_value.c_str()))); |
| 1356 base::StringPrintf("%s: %s", name.c_str(), log_value.c_str()))); | |
| 1357 } | 1335 } |
| 1358 dict->Set("headers", headers); | 1336 dict->Set("headers", headers); |
| 1359 return dict; | 1337 return dict; |
| 1360 } | 1338 } |
| 1361 | 1339 |
| 1362 // static | 1340 // static |
| 1363 bool HttpResponseHeaders::FromNetLogParam( | 1341 bool HttpResponseHeaders::FromNetLogParam( |
| 1364 const base::Value* event_param, | 1342 const base::Value* event_param, |
| 1365 scoped_refptr<HttpResponseHeaders>* http_response_headers) { | 1343 scoped_refptr<HttpResponseHeaders>* http_response_headers) { |
| 1366 *http_response_headers = NULL; | 1344 *http_response_headers = NULL; |
| 1367 | 1345 |
| 1368 const base::DictionaryValue* dict = NULL; | 1346 const base::DictionaryValue* dict = NULL; |
| 1369 const base::ListValue* header_list = NULL; | 1347 const base::ListValue* header_list = NULL; |
| 1370 | 1348 |
| 1371 if (!event_param || | 1349 if (!event_param || !event_param->GetAsDictionary(&dict) || |
| 1372 !event_param->GetAsDictionary(&dict) || | |
| 1373 !dict->GetList("headers", &header_list)) { | 1350 !dict->GetList("headers", &header_list)) { |
| 1374 return false; | 1351 return false; |
| 1375 } | 1352 } |
| 1376 | 1353 |
| 1377 std::string raw_headers; | 1354 std::string raw_headers; |
| 1378 for (base::ListValue::const_iterator it = header_list->begin(); | 1355 for (base::ListValue::const_iterator it = header_list->begin(); |
| 1379 it != header_list->end(); | 1356 it != header_list->end(); |
| 1380 ++it) { | 1357 ++it) { |
| 1381 std::string header_line; | 1358 std::string header_line; |
| 1382 if (!(*it)->GetAsString(&header_line)) | 1359 if (!(*it)->GetAsString(&header_line)) |
| 1383 return false; | 1360 return false; |
| 1384 | 1361 |
| 1385 raw_headers.append(header_line); | 1362 raw_headers.append(header_line); |
| 1386 raw_headers.push_back('\0'); | 1363 raw_headers.push_back('\0'); |
| 1387 } | 1364 } |
| 1388 raw_headers.push_back('\0'); | 1365 raw_headers.push_back('\0'); |
| 1389 *http_response_headers = new HttpResponseHeaders(raw_headers); | 1366 *http_response_headers = new HttpResponseHeaders(raw_headers); |
| 1390 return true; | 1367 return true; |
| 1391 } | 1368 } |
| 1392 | 1369 |
| 1393 bool HttpResponseHeaders::IsChunkEncoded() const { | 1370 bool HttpResponseHeaders::IsChunkEncoded() const { |
| 1394 // Ignore spurious chunked responses from HTTP/1.0 servers and proxies. | 1371 // Ignore spurious chunked responses from HTTP/1.0 servers and proxies. |
| 1395 return GetHttpVersion() >= HttpVersion(1, 1) && | 1372 return GetHttpVersion() >= HttpVersion(1, 1) && |
| 1396 HasHeaderValue("Transfer-Encoding", "chunked"); | 1373 HasHeaderValue("Transfer-Encoding", "chunked"); |
| 1397 } | 1374 } |
| 1398 | 1375 |
| 1399 #if defined(SPDY_PROXY_AUTH_ORIGIN) | 1376 #if defined(SPDY_PROXY_AUTH_ORIGIN) |
| 1400 bool HttpResponseHeaders::GetDataReductionProxyBypassDuration( | 1377 bool HttpResponseHeaders::GetDataReductionProxyBypassDuration( |
| 1401 const std::string& action_prefix, | 1378 const std::string& action_prefix, |
| 1402 base::TimeDelta* duration) const { | 1379 base::TimeDelta* duration) const { |
| 1403 void* iter = NULL; | 1380 void* iter = NULL; |
| 1404 std::string value; | 1381 std::string value; |
| 1405 std::string name = "chrome-proxy"; | 1382 std::string name = "chrome-proxy"; |
| 1406 | 1383 |
| 1407 while (EnumerateHeader(&iter, name, &value)) { | 1384 while (EnumerateHeader(&iter, name, &value)) { |
| 1408 if (value.size() > action_prefix.size()) { | 1385 if (value.size() > action_prefix.size()) { |
| 1409 if (LowerCaseEqualsASCII(value.begin(), | 1386 if (LowerCaseEqualsASCII(value.begin(), |
| 1410 value.begin() + action_prefix.size(), | 1387 value.begin() + action_prefix.size(), |
| 1411 action_prefix.c_str())) { | 1388 action_prefix.c_str())) { |
| 1412 int64 seconds; | 1389 int64 seconds; |
| 1413 if (!base::StringToInt64( | 1390 if (!base::StringToInt64( |
| 1414 StringPiece(value.begin() + action_prefix.size(), value.end()), | 1391 StringPiece(value.begin() + action_prefix.size(), value.end()), |
| 1415 &seconds) || seconds < 0) { | 1392 &seconds) || |
| 1393 seconds < 0) { |
| 1416 continue; // In case there is a well formed instruction. | 1394 continue; // In case there is a well formed instruction. |
| 1417 } | 1395 } |
| 1418 *duration = TimeDelta::FromSeconds(seconds); | 1396 *duration = TimeDelta::FromSeconds(seconds); |
| 1419 return true; | 1397 return true; |
| 1420 } | 1398 } |
| 1421 } | 1399 } |
| 1422 } | 1400 } |
| 1423 return false; | 1401 return false; |
| 1424 } | 1402 } |
| 1425 | 1403 |
| 1426 bool HttpResponseHeaders::GetDataReductionProxyInfo( | 1404 bool HttpResponseHeaders::GetDataReductionProxyInfo( |
| 1427 DataReductionProxyInfo* proxy_info) const { | 1405 DataReductionProxyInfo* proxy_info) const { |
| 1428 DCHECK(proxy_info); | 1406 DCHECK(proxy_info); |
| 1429 proxy_info->bypass_all = false; | 1407 proxy_info->bypass_all = false; |
| 1430 proxy_info->bypass_duration = base::TimeDelta(); | 1408 proxy_info->bypass_duration = base::TimeDelta(); |
| 1431 // Support header of the form Chrome-Proxy: bypass|block=<duration>, where | 1409 // Support header of the form Chrome-Proxy: bypass|block=<duration>, where |
| 1432 // <duration> is the number of seconds to wait before retrying | 1410 // <duration> is the number of seconds to wait before retrying |
| 1433 // the proxy. If the duration is 0, then the default proxy retry delay | 1411 // the proxy. If the duration is 0, then the default proxy retry delay |
| 1434 // (specified in |ProxyList::UpdateRetryInfoOnFallback|) will be used. | 1412 // (specified in |ProxyList::UpdateRetryInfoOnFallback|) will be used. |
| 1435 // 'bypass' instructs Chrome to bypass the currently connected data reduction | 1413 // 'bypass' instructs Chrome to bypass the currently connected data reduction |
| 1436 // proxy, whereas 'block' instructs Chrome to bypass all available data | 1414 // proxy, whereas 'block' instructs Chrome to bypass all available data |
| 1437 // reduction proxies. | 1415 // reduction proxies. |
| 1438 | 1416 |
| 1439 // 'block' takes precedence over 'bypass', so look for it first. | 1417 // 'block' takes precedence over 'bypass', so look for it first. |
| 1440 // TODO(bengr): Reduce checks for 'block' and 'bypass' to a single loop. | 1418 // TODO(bengr): Reduce checks for 'block' and 'bypass' to a single loop. |
| 1441 if (GetDataReductionProxyBypassDuration( | 1419 if (GetDataReductionProxyBypassDuration("block=", |
| 1442 "block=", &proxy_info->bypass_duration)) { | 1420 &proxy_info->bypass_duration)) { |
| 1443 proxy_info->bypass_all = true; | 1421 proxy_info->bypass_all = true; |
| 1444 return true; | 1422 return true; |
| 1445 } | 1423 } |
| 1446 | 1424 |
| 1447 // Next, look for 'bypass'. | 1425 // Next, look for 'bypass'. |
| 1448 if (GetDataReductionProxyBypassDuration( | 1426 if (GetDataReductionProxyBypassDuration("bypass=", |
| 1449 "bypass=", &proxy_info->bypass_duration)) { | 1427 &proxy_info->bypass_duration)) { |
| 1450 return true; | 1428 return true; |
| 1451 } | 1429 } |
| 1452 return false; | 1430 return false; |
| 1453 } | 1431 } |
| 1454 | 1432 |
| 1455 bool HttpResponseHeaders::IsDataReductionProxyResponse() const { | 1433 bool HttpResponseHeaders::IsDataReductionProxyResponse() const { |
| 1456 const size_t kVersionSize = 4; | 1434 const size_t kVersionSize = 4; |
| 1457 const char kDataReductionProxyViaValue[] = "Chrome-Compression-Proxy"; | 1435 const char kDataReductionProxyViaValue[] = "Chrome-Compression-Proxy"; |
| 1458 size_t value_len = strlen(kDataReductionProxyViaValue); | 1436 size_t value_len = strlen(kDataReductionProxyViaValue); |
| 1459 void* iter = NULL; | 1437 void* iter = NULL; |
| (...skipping 43 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
| 1503 // should not generate representation metadata other than Cache-Control, | 1481 // should not generate representation metadata other than Cache-Control, |
| 1504 // Content-Location, Date, ETag, Expires, and Vary. | 1482 // Content-Location, Date, ETag, Expires, and Vary. |
| 1505 return ProxyService::MISSING_VIA_HEADER; | 1483 return ProxyService::MISSING_VIA_HEADER; |
| 1506 } | 1484 } |
| 1507 // There is no bypass event. | 1485 // There is no bypass event. |
| 1508 return ProxyService::BYPASS_EVENT_TYPE_MAX; | 1486 return ProxyService::BYPASS_EVENT_TYPE_MAX; |
| 1509 } | 1487 } |
| 1510 #endif // defined(SPDY_PROXY_AUTH_ORIGIN) | 1488 #endif // defined(SPDY_PROXY_AUTH_ORIGIN) |
| 1511 | 1489 |
| 1512 } // namespace net | 1490 } // namespace net |
| OLD | NEW |