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

Side by Side Diff: Source/platform/network/ResourceResponse.cpp

Issue 229053004: Allow cache reuse of some requests with Cache-Control headers (Closed) Base URL: svn://svn.chromium.org/blink/trunk
Patch Set: Created 6 years, 8 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 unified diff | Download patch | Annotate | Revision Log
« no previous file with comments | « Source/platform/network/ResourceResponse.h ('k') | no next file » | no next file with comments »
Toggle Intra-line Diffs ('i') | Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
OLDNEW
1 /* 1 /*
2 * Copyright (C) 2006, 2008 Apple Inc. All rights reserved. 2 * Copyright (C) 2006, 2008 Apple Inc. All rights reserved.
3 * Copyright (C) 2009 Google Inc. All rights reserved. 3 * Copyright (C) 2009 Google Inc. All rights reserved.
4 * 4 *
5 * Redistribution and use in source and binary forms, with or without 5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions 6 * modification, are permitted provided that the following conditions
7 * are met: 7 * are met:
8 * 1. Redistributions of source code must retain the above copyright 8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer. 9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright 10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the 11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution. 12 * documentation and/or other materials provided with the distribution.
13 * 13 *
14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY 14 * THIS SOFTWARE IS PROVIDED BY APPLE COMPUTER, INC. ``AS IS'' AND ANY
15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 15 * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR 17 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE COMPUTER, INC. OR
18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, 18 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, 19 * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR 20 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY 21 * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 22 * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */ 25 */
26 26
27 #include "config.h" 27 #include "config.h"
28 #include "platform/network/ResourceResponse.h" 28 #include "platform/network/ResourceResponse.h"
29 29
30 #include "platform/network/HTTPParsers.h"
31 #include "wtf/CurrentTime.h" 30 #include "wtf/CurrentTime.h"
32 #include "wtf/MathExtras.h"
33 #include "wtf/StdLibExtras.h" 31 #include "wtf/StdLibExtras.h"
34 32
35 namespace WebCore { 33 namespace WebCore {
36 34
37 static void parseCacheHeader(const String& header, Vector<pair<String, String> > & result);
38
39 ResourceResponse::ResourceResponse() 35 ResourceResponse::ResourceResponse()
40 : m_expectedContentLength(0) 36 : m_expectedContentLength(0)
41 , m_httpStatusCode(0) 37 , m_httpStatusCode(0)
42 , m_lastModifiedDate(0) 38 , m_lastModifiedDate(0)
43 , m_wasCached(false) 39 , m_wasCached(false)
44 , m_connectionID(0) 40 , m_connectionID(0)
45 , m_connectionReused(false) 41 , m_connectionReused(false)
46 , m_isNull(true) 42 , m_isNull(true)
47 , m_haveParsedCacheControlHeader(false)
48 , m_haveParsedAgeHeader(false) 43 , m_haveParsedAgeHeader(false)
49 , m_haveParsedDateHeader(false) 44 , m_haveParsedDateHeader(false)
50 , m_haveParsedExpiresHeader(false) 45 , m_haveParsedExpiresHeader(false)
51 , m_haveParsedLastModifiedHeader(false) 46 , m_haveParsedLastModifiedHeader(false)
52 , m_cacheControlContainsNoCache(false)
53 , m_cacheControlContainsNoStore(false)
54 , m_cacheControlContainsMustRevalidate(false)
55 , m_cacheControlMaxAge(0.0)
56 , m_age(0.0) 47 , m_age(0.0)
57 , m_date(0.0) 48 , m_date(0.0)
58 , m_expires(0.0) 49 , m_expires(0.0)
59 , m_lastModified(0.0) 50 , m_lastModified(0.0)
60 , m_httpVersion(Unknown) 51 , m_httpVersion(Unknown)
61 , m_appCacheID(0) 52 , m_appCacheID(0)
62 , m_isMultipartPayload(false) 53 , m_isMultipartPayload(false)
63 , m_wasFetchedViaSPDY(false) 54 , m_wasFetchedViaSPDY(false)
64 , m_wasNpnNegotiated(false) 55 , m_wasNpnNegotiated(false)
65 , m_wasAlternateProtocolAvailable(false) 56 , m_wasAlternateProtocolAvailable(false)
66 , m_wasFetchedViaProxy(false) 57 , m_wasFetchedViaProxy(false)
67 , m_responseTime(0) 58 , m_responseTime(0)
68 , m_remotePort(0) 59 , m_remotePort(0)
69 { 60 {
70 } 61 }
71 62
72 ResourceResponse::ResourceResponse(const KURL& url, const AtomicString& mimeType , long long expectedLength, const AtomicString& textEncodingName, const String& filename) 63 ResourceResponse::ResourceResponse(const KURL& url, const AtomicString& mimeType , long long expectedLength, const AtomicString& textEncodingName, const String& filename)
73 : m_url(url) 64 : m_url(url)
74 , m_mimeType(mimeType) 65 , m_mimeType(mimeType)
75 , m_expectedContentLength(expectedLength) 66 , m_expectedContentLength(expectedLength)
76 , m_textEncodingName(textEncodingName) 67 , m_textEncodingName(textEncodingName)
77 , m_suggestedFilename(filename) 68 , m_suggestedFilename(filename)
78 , m_httpStatusCode(0) 69 , m_httpStatusCode(0)
79 , m_lastModifiedDate(0) 70 , m_lastModifiedDate(0)
80 , m_wasCached(false) 71 , m_wasCached(false)
81 , m_connectionID(0) 72 , m_connectionID(0)
82 , m_connectionReused(false) 73 , m_connectionReused(false)
83 , m_isNull(false) 74 , m_isNull(false)
84 , m_haveParsedCacheControlHeader(false)
85 , m_haveParsedAgeHeader(false) 75 , m_haveParsedAgeHeader(false)
86 , m_haveParsedDateHeader(false) 76 , m_haveParsedDateHeader(false)
87 , m_haveParsedExpiresHeader(false) 77 , m_haveParsedExpiresHeader(false)
88 , m_haveParsedLastModifiedHeader(false) 78 , m_haveParsedLastModifiedHeader(false)
89 , m_cacheControlContainsNoCache(false)
90 , m_cacheControlContainsNoStore(false)
91 , m_cacheControlContainsMustRevalidate(false)
92 , m_cacheControlMaxAge(0.0)
93 , m_age(0.0) 79 , m_age(0.0)
94 , m_date(0.0) 80 , m_date(0.0)
95 , m_expires(0.0) 81 , m_expires(0.0)
96 , m_lastModified(0.0) 82 , m_lastModified(0.0)
97 , m_httpVersion(Unknown) 83 , m_httpVersion(Unknown)
98 , m_appCacheID(0) 84 , m_appCacheID(0)
99 , m_isMultipartPayload(false) 85 , m_isMultipartPayload(false)
100 , m_wasFetchedViaSPDY(false) 86 , m_wasFetchedViaSPDY(false)
101 , m_wasNpnNegotiated(false) 87 , m_wasNpnNegotiated(false)
102 , m_wasAlternateProtocolAvailable(false) 88 , m_wasAlternateProtocolAvailable(false)
(...skipping 167 matching lines...) Expand 10 before | Expand all | Expand 10 after
270 const AtomicString& ResourceResponse::httpHeaderField(const AtomicString& name) const 256 const AtomicString& ResourceResponse::httpHeaderField(const AtomicString& name) const
271 { 257 {
272 return m_httpHeaderFields.get(name); 258 return m_httpHeaderFields.get(name);
273 } 259 }
274 260
275 const AtomicString& ResourceResponse::httpHeaderField(const char* name) const 261 const AtomicString& ResourceResponse::httpHeaderField(const char* name) const
276 { 262 {
277 return m_httpHeaderFields.get(name); 263 return m_httpHeaderFields.get(name);
278 } 264 }
279 265
266 static const AtomicString& cacheControlHeaderString()
267 {
268 DEFINE_STATIC_LOCAL(const AtomicString, cacheControlHeader, ("cache-control" , AtomicString::ConstructFromLiteral));
269 return cacheControlHeader;
270 }
271
272 static const AtomicString& pragmaHeaderString()
273 {
274 DEFINE_STATIC_LOCAL(const AtomicString, pragmaHeader, ("pragma", AtomicStrin g::ConstructFromLiteral));
275 return pragmaHeader;
276 }
277
280 void ResourceResponse::updateHeaderParsedState(const AtomicString& name) 278 void ResourceResponse::updateHeaderParsedState(const AtomicString& name)
281 { 279 {
282 DEFINE_STATIC_LOCAL(const AtomicString, ageHeader, ("age", AtomicString::Con structFromLiteral)); 280 DEFINE_STATIC_LOCAL(const AtomicString, ageHeader, ("age", AtomicString::Con structFromLiteral));
283 DEFINE_STATIC_LOCAL(const AtomicString, cacheControlHeader, ("cache-control" , AtomicString::ConstructFromLiteral));
284 DEFINE_STATIC_LOCAL(const AtomicString, dateHeader, ("date", AtomicString::C onstructFromLiteral)); 281 DEFINE_STATIC_LOCAL(const AtomicString, dateHeader, ("date", AtomicString::C onstructFromLiteral));
285 DEFINE_STATIC_LOCAL(const AtomicString, expiresHeader, ("expires", AtomicStr ing::ConstructFromLiteral)); 282 DEFINE_STATIC_LOCAL(const AtomicString, expiresHeader, ("expires", AtomicStr ing::ConstructFromLiteral));
286 DEFINE_STATIC_LOCAL(const AtomicString, lastModifiedHeader, ("last-modified" , AtomicString::ConstructFromLiteral)); 283 DEFINE_STATIC_LOCAL(const AtomicString, lastModifiedHeader, ("last-modified" , AtomicString::ConstructFromLiteral));
287 DEFINE_STATIC_LOCAL(const AtomicString, pragmaHeader, ("pragma", AtomicStrin g::ConstructFromLiteral));
288 284
289 if (equalIgnoringCase(name, ageHeader)) 285 if (equalIgnoringCase(name, ageHeader))
290 m_haveParsedAgeHeader = false; 286 m_haveParsedAgeHeader = false;
291 else if (equalIgnoringCase(name, cacheControlHeader) || equalIgnoringCase(na me, pragmaHeader)) 287 else if (equalIgnoringCase(name, cacheControlHeaderString()) || equalIgnorin gCase(name, pragmaHeaderString()))
292 m_haveParsedCacheControlHeader = false; 288 m_cacheControlHeader = CacheControlHeader();
293 else if (equalIgnoringCase(name, dateHeader)) 289 else if (equalIgnoringCase(name, dateHeader))
294 m_haveParsedDateHeader = false; 290 m_haveParsedDateHeader = false;
295 else if (equalIgnoringCase(name, expiresHeader)) 291 else if (equalIgnoringCase(name, expiresHeader))
296 m_haveParsedExpiresHeader = false; 292 m_haveParsedExpiresHeader = false;
297 else if (equalIgnoringCase(name, lastModifiedHeader)) 293 else if (equalIgnoringCase(name, lastModifiedHeader))
298 m_haveParsedLastModifiedHeader = false; 294 m_haveParsedLastModifiedHeader = false;
299 } 295 }
300 296
301 void ResourceResponse::setHTTPHeaderField(const AtomicString& name, const Atomic String& value) 297 void ResourceResponse::setHTTPHeaderField(const AtomicString& name, const Atomic String& value)
302 { 298 {
(...skipping 14 matching lines...) Expand all
317 void ResourceResponse::clearHTTPHeaderField(const AtomicString& name) 313 void ResourceResponse::clearHTTPHeaderField(const AtomicString& name)
318 { 314 {
319 m_httpHeaderFields.remove(name); 315 m_httpHeaderFields.remove(name);
320 } 316 }
321 317
322 const HTTPHeaderMap& ResourceResponse::httpHeaderFields() const 318 const HTTPHeaderMap& ResourceResponse::httpHeaderFields() const
323 { 319 {
324 return m_httpHeaderFields; 320 return m_httpHeaderFields;
325 } 321 }
326 322
327 void ResourceResponse::parseCacheControlDirectives() const 323 bool ResourceResponse::cacheControlContainsNoCache()
328 { 324 {
329 ASSERT(!m_haveParsedCacheControlHeader); 325 if (!m_cacheControlHeader.parsed)
330 326 m_cacheControlHeader = parseCacheControlDirectives(m_httpHeaderFields.ge t(cacheControlHeaderString()), m_httpHeaderFields.get(pragmaHeaderString()));
331 m_haveParsedCacheControlHeader = true; 327 return m_cacheControlHeader.containsNoCache;
332
333 m_cacheControlContainsMustRevalidate = false;
334 m_cacheControlContainsNoCache = false;
335 m_cacheControlMaxAge = std::numeric_limits<double>::quiet_NaN();
336
337 DEFINE_STATIC_LOCAL(const AtomicString, cacheControlString, ("cache-control" , AtomicString::ConstructFromLiteral));
338 DEFINE_STATIC_LOCAL(const AtomicString, noCacheDirective, ("no-cache", Atomi cString::ConstructFromLiteral));
339 DEFINE_STATIC_LOCAL(const AtomicString, noStoreDirective, ("no-store", Atomi cString::ConstructFromLiteral));
340 DEFINE_STATIC_LOCAL(const AtomicString, mustRevalidateDirective, ("must-reva lidate", AtomicString::ConstructFromLiteral));
341 DEFINE_STATIC_LOCAL(const AtomicString, maxAgeDirective, ("max-age", AtomicS tring::ConstructFromLiteral));
342
343 const AtomicString& cacheControlValue = m_httpHeaderFields.get(cacheControlS tring);
344 if (!cacheControlValue.isEmpty()) {
345 Vector<pair<String, String> > directives;
346 parseCacheHeader(cacheControlValue, directives);
347
348 size_t directivesSize = directives.size();
349 for (size_t i = 0; i < directivesSize; ++i) {
350 // RFC2616 14.9.1: A no-cache directive with a value is only meaning ful for proxy caches.
351 // It should be ignored by a browser level cache.
352 if (equalIgnoringCase(directives[i].first, noCacheDirective) && dire ctives[i].second.isEmpty())
353 m_cacheControlContainsNoCache = true;
354 else if (equalIgnoringCase(directives[i].first, noStoreDirective))
355 m_cacheControlContainsNoStore = true;
356 else if (equalIgnoringCase(directives[i].first, mustRevalidateDirect ive))
357 m_cacheControlContainsMustRevalidate = true;
358 else if (equalIgnoringCase(directives[i].first, maxAgeDirective)) {
359 if (!std::isnan(m_cacheControlMaxAge)) {
360 // First max-age directive wins if there are multiple ones.
361 continue;
362 }
363 bool ok;
364 double maxAge = directives[i].second.toDouble(&ok);
365 if (ok)
366 m_cacheControlMaxAge = maxAge;
367 }
368 }
369 }
370
371 if (!m_cacheControlContainsNoCache) {
372 // Handle Pragma: no-cache
373 // This is deprecated and equivalent to Cache-control: no-cache
374 // Don't bother tokenizing the value, it is not important
375 DEFINE_STATIC_LOCAL(const AtomicString, pragmaHeader, ("pragma", AtomicS tring::ConstructFromLiteral));
376 const AtomicString& pragmaValue = m_httpHeaderFields.get(pragmaHeader);
377
378 m_cacheControlContainsNoCache = pragmaValue.lower().contains(noCacheDire ctive);
379 }
380 } 328 }
381 329
382 bool ResourceResponse::cacheControlContainsNoCache() const 330 bool ResourceResponse::cacheControlContainsNoStore()
383 { 331 {
384 if (!m_haveParsedCacheControlHeader) 332 if (!m_cacheControlHeader.parsed)
385 parseCacheControlDirectives(); 333 m_cacheControlHeader = parseCacheControlDirectives(m_httpHeaderFields.ge t(cacheControlHeaderString()), m_httpHeaderFields.get(pragmaHeaderString()));
386 return m_cacheControlContainsNoCache; 334 return m_cacheControlHeader.containsNoStore;
387 } 335 }
388 336
389 bool ResourceResponse::cacheControlContainsNoStore() const 337 bool ResourceResponse::cacheControlContainsMustRevalidate()
390 { 338 {
391 if (!m_haveParsedCacheControlHeader) 339 if (!m_cacheControlHeader.parsed)
392 parseCacheControlDirectives(); 340 m_cacheControlHeader = parseCacheControlDirectives(m_httpHeaderFields.ge t(cacheControlHeaderString()), m_httpHeaderFields.get(pragmaHeaderString()));
393 return m_cacheControlContainsNoStore; 341 return m_cacheControlHeader.containsMustRevalidate;
394 }
395
396 bool ResourceResponse::cacheControlContainsMustRevalidate() const
397 {
398 if (!m_haveParsedCacheControlHeader)
399 parseCacheControlDirectives();
400 return m_cacheControlContainsMustRevalidate;
401 } 342 }
402 343
403 bool ResourceResponse::hasCacheValidatorFields() const 344 bool ResourceResponse::hasCacheValidatorFields() const
404 { 345 {
405 DEFINE_STATIC_LOCAL(const AtomicString, lastModifiedHeader, ("last-modified" , AtomicString::ConstructFromLiteral)); 346 DEFINE_STATIC_LOCAL(const AtomicString, lastModifiedHeader, ("last-modified" , AtomicString::ConstructFromLiteral));
406 DEFINE_STATIC_LOCAL(const AtomicString, eTagHeader, ("etag", AtomicString::C onstructFromLiteral)); 347 DEFINE_STATIC_LOCAL(const AtomicString, eTagHeader, ("etag", AtomicString::C onstructFromLiteral));
407 return !m_httpHeaderFields.get(lastModifiedHeader).isEmpty() || !m_httpHeade rFields.get(eTagHeader).isEmpty(); 348 return !m_httpHeaderFields.get(lastModifiedHeader).isEmpty() || !m_httpHeade rFields.get(eTagHeader).isEmpty();
408 } 349 }
409 350
410 double ResourceResponse::cacheControlMaxAge() const 351 double ResourceResponse::cacheControlMaxAge()
411 { 352 {
412 if (!m_haveParsedCacheControlHeader) 353 if (!m_cacheControlHeader.parsed)
413 parseCacheControlDirectives(); 354 m_cacheControlHeader = parseCacheControlDirectives(m_httpHeaderFields.ge t(cacheControlHeaderString()), m_httpHeaderFields.get(pragmaHeaderString()));
414 return m_cacheControlMaxAge; 355 return m_cacheControlHeader.maxAge;
415 } 356 }
416 357
417 static double parseDateValueInHeader(const HTTPHeaderMap& headers, const AtomicS tring& headerName) 358 static double parseDateValueInHeader(const HTTPHeaderMap& headers, const AtomicS tring& headerName)
418 { 359 {
419 const AtomicString& headerValue = headers.get(headerName); 360 const AtomicString& headerValue = headers.get(headerName);
420 if (headerValue.isEmpty()) 361 if (headerValue.isEmpty())
421 return std::numeric_limits<double>::quiet_NaN(); 362 return std::numeric_limits<double>::quiet_NaN();
422 // This handles all date formats required by RFC2616: 363 // This handles all date formats required by RFC2616:
423 // Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123 364 // Sun, 06 Nov 1994 08:49:37 GMT ; RFC 822, updated by RFC 1123
424 // Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036 365 // Sunday, 06-Nov-94 08:49:37 GMT ; RFC 850, obsoleted by RFC 1036
(...skipping 153 matching lines...) Expand 10 before | Expand all | Expand 10 after
578 return false; 519 return false;
579 if (a.httpHeaderFields() != b.httpHeaderFields()) 520 if (a.httpHeaderFields() != b.httpHeaderFields())
580 return false; 521 return false;
581 if (a.resourceLoadTiming() && b.resourceLoadTiming() && *a.resourceLoadTimin g() == *b.resourceLoadTiming()) 522 if (a.resourceLoadTiming() && b.resourceLoadTiming() && *a.resourceLoadTimin g() == *b.resourceLoadTiming())
582 return true; 523 return true;
583 if (a.resourceLoadTiming() != b.resourceLoadTiming()) 524 if (a.resourceLoadTiming() != b.resourceLoadTiming())
584 return false; 525 return false;
585 return true; 526 return true;
586 } 527 }
587 528
588 static bool isCacheHeaderSeparator(UChar c)
589 {
590 // See RFC 2616, Section 2.2
591 switch (c) {
592 case '(':
593 case ')':
594 case '<':
595 case '>':
596 case '@':
597 case ',':
598 case ';':
599 case ':':
600 case '\\':
601 case '"':
602 case '/':
603 case '[':
604 case ']':
605 case '?':
606 case '=':
607 case '{':
608 case '}':
609 case ' ':
610 case '\t':
611 return true;
612 default:
613 return false;
614 }
615 } 529 }
616
617 static bool isControlCharacter(UChar c)
618 {
619 return c < ' ' || c == 127;
620 }
621
622 static inline String trimToNextSeparator(const String& str)
623 {
624 return str.substring(0, str.find(isCacheHeaderSeparator));
625 }
626
627 static void parseCacheHeader(const String& header, Vector<pair<String, String> > & result)
628 {
629 const String safeHeader = header.removeCharacters(isControlCharacter);
630 unsigned max = safeHeader.length();
631 for (unsigned pos = 0; pos < max; /* pos incremented in loop */) {
632 size_t nextCommaPosition = safeHeader.find(',', pos);
633 size_t nextEqualSignPosition = safeHeader.find('=', pos);
634 if (nextEqualSignPosition != kNotFound && (nextEqualSignPosition < nextC ommaPosition || nextCommaPosition == kNotFound)) {
635 // Get directive name, parse right hand side of equal sign, then add to map
636 String directive = trimToNextSeparator(safeHeader.substring(pos, nex tEqualSignPosition - pos).stripWhiteSpace());
637 pos += nextEqualSignPosition - pos + 1;
638
639 String value = safeHeader.substring(pos, max - pos).stripWhiteSpace( );
640 if (value[0] == '"') {
641 // The value is a quoted string
642 size_t nextDoubleQuotePosition = value.find('"', 1);
643 if (nextDoubleQuotePosition != kNotFound) {
644 // Store the value as a quoted string without quotes
645 result.append(pair<String, String>(directive, value.substrin g(1, nextDoubleQuotePosition - 1).stripWhiteSpace()));
646 pos += (safeHeader.find('"', pos) - pos) + nextDoubleQuotePo sition + 1;
647 // Move past next comma, if there is one
648 size_t nextCommaPosition2 = safeHeader.find(',', pos);
649 if (nextCommaPosition2 != kNotFound)
650 pos += nextCommaPosition2 - pos + 1;
651 else
652 return; // Parse error if there is anything left with no comma
653 } else {
654 // Parse error; just use the rest as the value
655 result.append(pair<String, String>(directive, trimToNextSepa rator(value.substring(1, value.length() - 1).stripWhiteSpace())));
656 return;
657 }
658 } else {
659 // The value is a token until the next comma
660 size_t nextCommaPosition2 = value.find(',');
661 if (nextCommaPosition2 != kNotFound) {
662 // The value is delimited by the next comma
663 result.append(pair<String, String>(directive, trimToNextSepa rator(value.substring(0, nextCommaPosition2).stripWhiteSpace())));
664 pos += (safeHeader.find(',', pos) - pos) + 1;
665 } else {
666 // The rest is the value; no change to value needed
667 result.append(pair<String, String>(directive, trimToNextSepa rator(value)));
668 return;
669 }
670 }
671 } else if (nextCommaPosition != kNotFound && (nextCommaPosition < nextEq ualSignPosition || nextEqualSignPosition == kNotFound)) {
672 // Add directive to map with empty string as value
673 result.append(pair<String, String>(trimToNextSeparator(safeHeader.su bstring(pos, nextCommaPosition - pos).stripWhiteSpace()), ""));
674 pos += nextCommaPosition - pos + 1;
675 } else {
676 // Add last directive to map with empty string as value
677 result.append(pair<String, String>(trimToNextSeparator(safeHeader.su bstring(pos, max - pos).stripWhiteSpace()), ""));
678 return;
679 }
680 }
681 }
682
683 }
OLDNEW
« no previous file with comments | « Source/platform/network/ResourceResponse.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698