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

Side by Side Diff: third_party/WebKit/Source/modules/fetch/FetchHeaderList.cpp

Issue 2787003002: Fetch API: Stop lowercasing header names. (Closed)
Patch Set: Fix failing tests Created 3 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
OLDNEW
1 // Copyright 2014 The Chromium Authors. All rights reserved. 1 // Copyright 2014 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 #include "modules/fetch/FetchHeaderList.h" 5 #include "modules/fetch/FetchHeaderList.h"
6 6
7 #include <algorithm>
8 #include <utility>
7 #include "platform/loader/fetch/FetchUtils.h" 9 #include "platform/loader/fetch/FetchUtils.h"
8 #include "platform/network/HTTPParsers.h" 10 #include "platform/network/HTTPParsers.h"
9 #include "wtf/PtrUtil.h" 11 #include "wtf/text/StringBuilder.h"
10 #include <algorithm>
11 12
12 namespace blink { 13 namespace blink {
13 14
14 FetchHeaderList* FetchHeaderList::create() { 15 FetchHeaderList* FetchHeaderList::create() {
15 return new FetchHeaderList(); 16 return new FetchHeaderList();
16 } 17 }
17 18
18 FetchHeaderList* FetchHeaderList::clone() const { 19 FetchHeaderList* FetchHeaderList::clone() const {
19 FetchHeaderList* list = create(); 20 FetchHeaderList* list = create();
20 for (size_t i = 0; i < m_headerList.size(); ++i) 21 for (const auto& header : m_headerList)
21 list->append(m_headerList[i]->first, m_headerList[i]->second); 22 list->append(header.first, header.second);
22 return list; 23 return list;
23 } 24 }
24 25
25 FetchHeaderList::FetchHeaderList() {} 26 FetchHeaderList::FetchHeaderList() {}
26 27
27 FetchHeaderList::~FetchHeaderList() {} 28 FetchHeaderList::~FetchHeaderList() {}
28 29
29 void FetchHeaderList::append(const String& name, const String& value) { 30 void FetchHeaderList::append(const String& name, const String& value) {
31 // https://fetch.spec.whatwg.org/#concept-header-list-append
30 // "To append a name/value (|name|/|value|) pair to a header list (|list|), 32 // "To append a name/value (|name|/|value|) pair to a header list (|list|),
31 // append a new header whose name is |name|, byte lowercased, and value is 33 // run these steps:
32 // |value|, to |list|." 34 // 1. If |list| contains |name|, then set |name| to the first such header’s
33 m_headerList.push_back(WTF::wrapUnique(new Header(name.lower(), value))); 35 // name. This reuses the casing of the name of the header already in the
36 // header list, if any. If there are multiple matched headers their names
37 // will all be identical.
38 // 2. Append a new header whose name is |name| and |value| is |value| to
39 // |list|."
40 const auto& header = m_headerList.find(name);
41 if (header != m_headerList.end())
42 m_headerList.insert(std::make_pair(header->first, value));
43 else
44 m_headerList.insert(std::make_pair(name, value));
34 } 45 }
35 46
36 void FetchHeaderList::set(const String& name, const String& value) { 47 void FetchHeaderList::set(const String& name, const String& value) {
48 // https://fetch.spec.whatwg.org/#concept-header-list-set
37 // "To set a name/value (|name|/|value|) pair in a header list (|list|), run 49 // "To set a name/value (|name|/|value|) pair in a header list (|list|), run
38 // these steps: 50 // these steps:
39 // 1. Byte lowercase |name|. 51 // 1. If |list| contains |name|, then set the value of the first such header
40 // 2. If there are any headers in |list| whose name is |name|, set the value 52 // to |value| and remove the others.
41 // of the first such header to |value| and remove the others. 53 // 2. Otherwise, append a new header whose name is |name| and value is
42 // 3. Otherwise, append a new header whose name is |name| and value is 54 // |value| to |list|."
43 // |value|, to |list|." 55 const auto& existingHeader = m_headerList.find(name);
44 const String lowercasedName = name.lower(); 56 const FetchHeaderList::Header newHeader = std::make_pair(
45 for (size_t i = 0; i < m_headerList.size(); ++i) { 57 existingHeader != m_headerList.end() ? existingHeader->first : name,
46 if (m_headerList[i]->first == lowercasedName) { 58 value);
47 m_headerList[i]->second = value; 59 m_headerList.erase(name);
48 for (size_t j = i + 1; j < m_headerList.size();) { 60 m_headerList.insert(newHeader);
49 if (m_headerList[j]->first == lowercasedName)
50 m_headerList.erase(j);
51 else
52 ++j;
53 }
54 return;
55 }
56 }
57 m_headerList.push_back(WTF::makeUnique<Header>(lowercasedName, value));
58 } 61 }
59 62
60 String FetchHeaderList::extractMIMEType() const { 63 String FetchHeaderList::extractMIMEType() const {
61 // To extract a MIME type from a header list (headers), run these steps: 64 // To extract a MIME type from a header list (headers), run these steps:
62 // 1. Let MIMEType be the result of parsing `Content-Type` in headers. 65 // 1. Let MIMEType be the result of parsing `Content-Type` in headers.
63 String mimeType; 66 String mimeType;
64 if (!get("Content-Type", mimeType)) { 67 if (!get("Content-Type", mimeType)) {
65 // 2. If MIMEType is null or failure, return the empty byte sequence. 68 // 2. If MIMEType is null or failure, return the empty byte sequence.
66 return String(); 69 return String();
67 } 70 }
68 // 3. Return MIMEType, byte lowercased. 71 // 3. Return MIMEType, byte lowercased.
69 return mimeType.lower(); 72 return mimeType.lower();
70 } 73 }
71 74
72 size_t FetchHeaderList::size() const { 75 size_t FetchHeaderList::size() const {
73 return m_headerList.size(); 76 return m_headerList.size();
74 } 77 }
75 78
76 void FetchHeaderList::remove(const String& name) { 79 void FetchHeaderList::remove(const String& name) {
77 // "To delete a name (|name|) from a header list (|list|), remove all headers 80 // https://fetch.spec.whatwg.org/#concept-header-list-delete
78 // whose name is |name|, byte lowercased, from |list|." 81 // "To delete a name (name) from a header list (list), remove all headers
79 const String lowercasedName = name.lower(); 82 // whose name is a byte-case-insensitive match for name from list."
80 for (size_t i = 0; i < m_headerList.size();) { 83 m_headerList.erase(name);
81 if (m_headerList[i]->first == lowercasedName)
82 m_headerList.erase(i);
83 else
84 ++i;
85 }
86 } 84 }
87 85
88 bool FetchHeaderList::get(const String& name, String& result) const { 86 bool FetchHeaderList::get(const String& name, String& result) const {
89 const String lowercasedName = name.lower(); 87 // https://fetch.spec.whatwg.org/#concept-header-list-combine
88 // "To combine a name/value (|name|/|value|) pair in a header list (|list|),
89 // run these steps:
90 // 1. If |list| contains |name|, then set the value of the first such header
91 // to its value, followed by 0x2C 0x20, followed by |value|.
92 // 2. Otherwise, append a new header whose name is |name| and value is
93 // |value| to |list|."
94 StringBuilder resultBuilder;
90 bool found = false; 95 bool found = false;
91 for (const auto& header : m_headerList) { 96 const auto& range = m_headerList.equal_range(name);
92 if (header->first == lowercasedName) { 97 for (auto header = range.first; header != range.second; ++header) {
93 if (!found) { 98 if (!found) {
94 result = ""; 99 resultBuilder.append(header->second);
95 result.append(header->second); 100 found = true;
96 found = true; 101 } else {
97 } else { 102 // TODO(rakuco): This must be ", " instead. crbug.com/700434.
98 result.append(","); 103 resultBuilder.append(',');
99 result.append(header->second); 104 resultBuilder.append(header->second);
100 }
101 } 105 }
102 } 106 }
107 if (found)
108 result = resultBuilder.toString();
103 return found; 109 return found;
104 } 110 }
105 111
112 // This is going to be removed: see crbug.com/645492.
106 void FetchHeaderList::getAll(const String& name, Vector<String>& result) const { 113 void FetchHeaderList::getAll(const String& name, Vector<String>& result) const {
107 const String lowercasedName = name.lower();
108 result.clear(); 114 result.clear();
109 for (size_t i = 0; i < m_headerList.size(); ++i) { 115 const auto& range = m_headerList.equal_range(name);
110 if (m_headerList[i]->first == lowercasedName) 116 for (auto header = range.first; header != range.second; ++header) {
111 result.push_back(m_headerList[i]->second); 117 result.push_back(header->second);
112 } 118 }
113 } 119 }
114 120
115 bool FetchHeaderList::has(const String& name) const { 121 bool FetchHeaderList::has(const String& name) const {
116 const String lowercasedName = name.lower(); 122 // https://fetch.spec.whatwg.org/#header-list-contains
117 for (size_t i = 0; i < m_headerList.size(); ++i) { 123 // "A header list (|list|) contains a name (|name|) if |list| contains a
118 if (m_headerList[i]->first == lowercasedName) 124 // header whose name is a byte-case-insensitive match for |name|."
119 return true; 125 return m_headerList.find(name) != m_headerList.end();
120 }
121 return false;
122 } 126 }
123 127
124 void FetchHeaderList::clearList() { 128 void FetchHeaderList::clearList() {
125 m_headerList.clear(); 129 m_headerList.clear();
126 } 130 }
127 131
128 bool FetchHeaderList::containsNonSimpleHeader() const { 132 bool FetchHeaderList::containsNonSimpleHeader() const {
129 for (size_t i = 0; i < m_headerList.size(); ++i) { 133 return std::any_of(
130 if (!FetchUtils::isSimpleHeader(AtomicString(m_headerList[i]->first), 134 m_headerList.begin(), m_headerList.end(), [](const Header& header) {
131 AtomicString(m_headerList[i]->second))) 135 return !FetchUtils::isSimpleHeader(AtomicString(header.first),
132 return true; 136 AtomicString(header.second));
133 } 137 });
134 return false;
135 } 138 }
136 139
137 void FetchHeaderList::sortAndCombine() { 140 Vector<FetchHeaderList::Header> FetchHeaderList::sortAndCombine() const {
138 // https://fetch.spec.whatwg.org/#concept-header-list-sort-and-combine 141 // https://fetch.spec.whatwg.org/#concept-header-list-sort-and-combine
139 // "To sort and combine a header list..." 142 // "To sort and combine a header list (|list|), run these steps:
140 if (m_headerList.isEmpty()) 143 // 1. Let |headers| be an empty list of name-value pairs with the key being
141 return; 144 // the name and value the value.
142 145 // 2. Let |names| be all the names of the headers in |list|, byte-lowercased,
143 std::sort( 146 // with duplicates removed, and finally sorted lexicographically.
144 m_headerList.begin(), m_headerList.end(), 147 // 3. For each |name| in |names|, run these substeps:
145 [](const std::unique_ptr<Header>& a, const std::unique_ptr<Header>& b) { 148 // 1. Let |value| be the combined value given |name| and |list|.
146 return WTF::codePointCompareLessThan(a->first, b->first); 149 // 2. Append |name-value| to |headers|.
147 }); 150 // 4. Return |headers|."
148 151 Vector<FetchHeaderList::Header> ret;
149 for (size_t index = m_headerList.size() - 1; index > 0; --index) { 152 for (auto it = m_headerList.begin(); it != m_headerList.end();) {
150 if (m_headerList[index - 1]->first == m_headerList[index]->first) { 153 const String& headerName = it->first.lower();
151 m_headerList[index - 1]->second.append(","); 154 String combinedValue;
152 m_headerList[index - 1]->second.append(m_headerList[index]->second); 155 get(headerName, combinedValue);
153 m_headerList.erase(index, 1); 156 ret.emplace_back(std::make_pair(headerName, combinedValue));
154 } 157 // Skip to the next distinct key.
158 it = m_headerList.upper_bound(headerName);
155 } 159 }
160 return ret;
156 } 161 }
157 162
158 bool FetchHeaderList::isValidHeaderName(const String& name) { 163 bool FetchHeaderList::isValidHeaderName(const String& name) {
159 // "A name is a case-insensitive byte sequence that matches the field-name 164 // "A name is a case-insensitive byte sequence that matches the field-name
160 // token production." 165 // token production."
161 return isValidHTTPToken(name); 166 return isValidHTTPToken(name);
162 } 167 }
163 168
164 bool FetchHeaderList::isValidHeaderValue(const String& value) { 169 bool FetchHeaderList::isValidHeaderValue(const String& value) {
165 // "A value is a byte sequence that matches the field-value token production 170 // "A value is a byte sequence that matches the field-value token production
166 // and contains no 0x0A or 0x0D bytes." 171 // and contains no 0x0A or 0x0D bytes."
167 return isValidHTTPHeaderValue(value); 172 return isValidHTTPHeaderValue(value);
168 } 173 }
169 174
170 } // namespace blink 175 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698