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

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

Issue 2787003002: Fetch API: Stop lowercasing header names. (Closed)
Patch Set: Rebase for landing 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> 7 #include <algorithm>
8 #include <utility>
8 #include "platform/loader/fetch/FetchUtils.h" 9 #include "platform/loader/fetch/FetchUtils.h"
9 #include "platform/network/HTTPParsers.h" 10 #include "platform/network/HTTPParsers.h"
10 #include "platform/wtf/PtrUtil.h" 11 #include "platform/wtf/text/StringBuilder.h"
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 < header_list_.size(); ++i) 21 for (const auto& header : header_list_)
21 list->Append(header_list_[i]->first, header_list_[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 header_list_.push_back( 35 // name. This reuses the casing of the name of the header already in the
34 WTF::WrapUnique(new Header(name.DeprecatedLower(), value))); 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 auto header = header_list_.find(name);
41 if (header != header_list_.end())
42 header_list_.insert(std::make_pair(header->first, value));
43 else
44 header_list_.insert(std::make_pair(name, value));
35 } 45 }
36 46
37 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
38 // "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
39 // these steps: 50 // these steps:
40 // 1. Byte lowercase |name|. 51 // 1. If |list| contains |name|, then set the value of the first such header
41 // 2. If there are any headers in |list| whose name is |name|, set the value 52 // to |value| and remove the others.
42 // 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
43 // 3. Otherwise, append a new header whose name is |name| and value is 54 // |value| to |list|."
44 // |value|, to |list|." 55 auto existingHeader = header_list_.find(name);
45 const String lowercased_name = name.DeprecatedLower(); 56 const FetchHeaderList::Header newHeader = std::make_pair(
46 for (size_t i = 0; i < header_list_.size(); ++i) { 57 existingHeader != header_list_.end() ? existingHeader->first : name,
47 if (header_list_[i]->first == lowercased_name) { 58 value);
48 header_list_[i]->second = value; 59 header_list_.erase(name);
49 for (size_t j = i + 1; j < header_list_.size();) { 60 header_list_.insert(newHeader);
50 if (header_list_[j]->first == lowercased_name)
51 header_list_.erase(j);
52 else
53 ++j;
54 }
55 return;
56 }
57 }
58 header_list_.push_back(WTF::MakeUnique<Header>(lowercased_name, value));
59 } 61 }
60 62
61 String FetchHeaderList::ExtractMIMEType() const { 63 String FetchHeaderList::ExtractMIMEType() const {
62 // 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:
63 // 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.
64 String mime_type; 66 String mime_type;
65 if (!Get("Content-Type", mime_type)) { 67 if (!Get("Content-Type", mime_type)) {
66 // 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.
67 return String(); 69 return String();
68 } 70 }
69 // 3. Return MIMEType, byte lowercased. 71 // 3. Return MIMEType, byte lowercased.
70 return mime_type.DeprecatedLower(); 72 return mime_type.DeprecatedLower();
71 } 73 }
72 74
73 size_t FetchHeaderList::size() const { 75 size_t FetchHeaderList::size() const {
74 return header_list_.size(); 76 return header_list_.size();
75 } 77 }
76 78
77 void FetchHeaderList::Remove(const String& name) { 79 void FetchHeaderList::Remove(const String& name) {
78 // "To delete a name (|name|) from a header list (|list|), remove all headers 80 // https://fetch.spec.whatwg.org/#concept-header-list-delete
79 // whose name is |name|, byte lowercased, from |list|." 81 // "To delete a name (name) from a header list (list), remove all headers
80 const String lowercased_name = name.DeprecatedLower(); 82 // whose name is a byte-case-insensitive match for name from list."
81 for (size_t i = 0; i < header_list_.size();) { 83 header_list_.erase(name);
82 if (header_list_[i]->first == lowercased_name)
83 header_list_.erase(i);
84 else
85 ++i;
86 }
87 } 84 }
88 85
89 bool FetchHeaderList::Get(const String& name, String& result) const { 86 bool FetchHeaderList::Get(const String& name, String& result) const {
90 const String lowercased_name = name.DeprecatedLower(); 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;
91 bool found = false; 95 bool found = false;
92 for (const auto& header : header_list_) { 96 auto range = header_list_.equal_range(name);
93 if (header->first == lowercased_name) { 97 for (auto header = range.first; header != range.second; ++header) {
94 if (!found) { 98 if (!found) {
95 result = ""; 99 resultBuilder.Append(header->second);
96 result.Append(header->second); 100 found = true;
97 found = true; 101 } else {
98 } else { 102 // TODO(rakuco): This must be ", " instead. crbug.com/700434.
99 result.Append(","); 103 resultBuilder.Append(',');
100 result.Append(header->second); 104 resultBuilder.Append(header->second);
101 }
102 } 105 }
103 } 106 }
107 if (found)
108 result = resultBuilder.ToString();
104 return found; 109 return found;
105 } 110 }
106 111
112 // This is going to be removed: see crbug.com/645492.
107 void FetchHeaderList::GetAll(const String& name, Vector<String>& result) const { 113 void FetchHeaderList::GetAll(const String& name, Vector<String>& result) const {
108 const String lowercased_name = name.DeprecatedLower();
109 result.Clear(); 114 result.Clear();
110 for (size_t i = 0; i < header_list_.size(); ++i) { 115 auto range = header_list_.equal_range(name);
111 if (header_list_[i]->first == lowercased_name) 116 for (auto header = range.first; header != range.second; ++header) {
112 result.push_back(header_list_[i]->second); 117 result.push_back(header->second);
113 } 118 }
114 } 119 }
115 120
116 bool FetchHeaderList::Has(const String& name) const { 121 bool FetchHeaderList::Has(const String& name) const {
117 const String lowercased_name = name.DeprecatedLower(); 122 // https://fetch.spec.whatwg.org/#header-list-contains
118 for (size_t i = 0; i < header_list_.size(); ++i) { 123 // "A header list (|list|) contains a name (|name|) if |list| contains a
119 if (header_list_[i]->first == lowercased_name) 124 // header whose name is a byte-case-insensitive match for |name|."
120 return true; 125 return header_list_.find(name) != header_list_.end();
121 }
122 return false;
123 } 126 }
124 127
125 void FetchHeaderList::ClearList() { 128 void FetchHeaderList::ClearList() {
126 header_list_.Clear(); 129 header_list_.clear();
127 } 130 }
128 131
129 bool FetchHeaderList::ContainsNonSimpleHeader() const { 132 bool FetchHeaderList::ContainsNonSimpleHeader() const {
130 for (size_t i = 0; i < header_list_.size(); ++i) { 133 return std::any_of(
131 if (!FetchUtils::IsSimpleHeader(AtomicString(header_list_[i]->first), 134 header_list_.cbegin(), header_list_.cend(), [](const Header& header) {
132 AtomicString(header_list_[i]->second))) 135 return !FetchUtils::IsSimpleHeader(AtomicString(header.first),
133 return true; 136 AtomicString(header.second));
134 } 137 });
135 return false;
136 } 138 }
137 139
138 void FetchHeaderList::SortAndCombine() { 140 Vector<FetchHeaderList::Header> FetchHeaderList::SortAndCombine() const {
139 // https://fetch.spec.whatwg.org/#concept-header-list-sort-and-combine 141 // https://fetch.spec.whatwg.org/#concept-header-list-sort-and-combine
140 // "To sort and combine a header list..." 142 // "To sort and combine a header list (|list|), run these steps:
141 if (header_list_.IsEmpty()) 143 // 1. Let |headers| be an empty list of name-value pairs with the key being
142 return; 144 // the name and value the value.
143 145 // 2. Let |names| be all the names of the headers in |list|, byte-lowercased,
144 std::sort( 146 // with duplicates removed, and finally sorted lexicographically.
145 header_list_.begin(), header_list_.end(), 147 // 3. For each |name| in |names|, run these substeps:
146 [](const std::unique_ptr<Header>& a, const std::unique_ptr<Header>& b) { 148 // 1. Let |value| be the combined value given |name| and |list|.
147 return WTF::CodePointCompareLessThan(a->first, b->first); 149 // 2. Append |name-value| to |headers|.
148 }); 150 // 4. Return |headers|."
149 151 Vector<FetchHeaderList::Header> ret;
150 for (size_t index = header_list_.size() - 1; index > 0; --index) { 152 for (auto it = header_list_.cbegin(); it != header_list_.cend();) {
151 if (header_list_[index - 1]->first == header_list_[index]->first) { 153 const String& headerName = it->first.LowerASCII();
152 header_list_[index - 1]->second.Append(","); 154 String combinedValue;
153 header_list_[index - 1]->second.Append(header_list_[index]->second); 155 Get(headerName, combinedValue);
154 header_list_.erase(index, 1); 156 ret.emplace_back(std::make_pair(headerName, combinedValue));
155 } 157 // Skip to the next distinct key.
158 it = header_list_.upper_bound(headerName);
156 } 159 }
160 return ret;
157 } 161 }
158 162
159 bool FetchHeaderList::IsValidHeaderName(const String& name) { 163 bool FetchHeaderList::IsValidHeaderName(const String& name) {
160 // "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
161 // token production." 165 // token production."
162 return IsValidHTTPToken(name); 166 return IsValidHTTPToken(name);
163 } 167 }
164 168
165 bool FetchHeaderList::IsValidHeaderValue(const String& value) { 169 bool FetchHeaderList::IsValidHeaderValue(const String& value) {
166 // "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
167 // and contains no 0x0A or 0x0D bytes." 171 // and contains no 0x0A or 0x0D bytes."
168 return IsValidHTTPHeaderValue(value); 172 return IsValidHTTPHeaderValue(value);
169 } 173 }
170 174
171 } // namespace blink 175 } // namespace blink
OLDNEW

Powered by Google App Engine
This is Rietveld 408576698