| OLD | NEW |
| (Empty) |
| 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 | |
| 3 // found in the LICENSE file. | |
| 4 | |
| 5 #include "config.h" | |
| 6 #include "modules/serviceworkers/Headers.h" | |
| 7 | |
| 8 #include "bindings/core/v8/Dictionary.h" | |
| 9 #include "bindings/core/v8/ExceptionState.h" | |
| 10 #include "bindings/core/v8/V8IteratorResultValue.h" | |
| 11 #include "core/dom/Iterator.h" | |
| 12 #include "core/fetch/FetchUtils.h" | |
| 13 #include "wtf/NotFound.h" | |
| 14 #include "wtf/PassRefPtr.h" | |
| 15 #include "wtf/RefPtr.h" | |
| 16 #include "wtf/text/WTFString.h" | |
| 17 | |
| 18 namespace blink { | |
| 19 | |
| 20 namespace { | |
| 21 | |
| 22 class HeadersIterator final : public Iterator { | |
| 23 public: | |
| 24 // Only KeyValue is currently used; the other types are to support | |
| 25 // Map-like iteration with entries(), keys() and values(), but this has | |
| 26 // not yet been added to any spec. | |
| 27 enum IterationType { KeyValue, Key, Value }; | |
| 28 | |
| 29 HeadersIterator(FetchHeaderList* headers, IterationType type) : m_headers(he
aders), m_type(type), m_current(0) { } | |
| 30 | |
| 31 virtual ScriptValue next(ScriptState* scriptState, ExceptionState& exception
) override | |
| 32 { | |
| 33 // FIXME: This simply advances an index and returns the next value if | |
| 34 // any, so if the iterated object is mutated values may be skipped. | |
| 35 if (m_current >= m_headers->size()) | |
| 36 return v8IteratorResultDone(scriptState); | |
| 37 | |
| 38 const FetchHeaderList::Header& header = m_headers->entry(m_current++); | |
| 39 switch (m_type) { | |
| 40 case KeyValue: { | |
| 41 Vector<String> pair; | |
| 42 pair.append(header.first); | |
| 43 pair.append(header.second); | |
| 44 return v8IteratorResult(scriptState, pair); | |
| 45 } | |
| 46 case Key: | |
| 47 return v8IteratorResult(scriptState, header.first); | |
| 48 case Value: | |
| 49 return v8IteratorResult(scriptState, header.second); | |
| 50 } | |
| 51 ASSERT_NOT_REACHED(); | |
| 52 return ScriptValue(); | |
| 53 } | |
| 54 | |
| 55 virtual ScriptValue next(ScriptState* scriptState, ScriptValue, ExceptionSta
te& exceptionState) override | |
| 56 { | |
| 57 return next(scriptState, exceptionState); | |
| 58 } | |
| 59 | |
| 60 virtual void trace(Visitor* visitor) | |
| 61 { | |
| 62 Iterator::trace(visitor); | |
| 63 visitor->trace(m_headers); | |
| 64 } | |
| 65 | |
| 66 private: | |
| 67 const Member<FetchHeaderList> m_headers; | |
| 68 const IterationType m_type; | |
| 69 size_t m_current; | |
| 70 }; | |
| 71 | |
| 72 } // namespace | |
| 73 | |
| 74 Headers* Headers::create() | |
| 75 { | |
| 76 return new Headers; | |
| 77 } | |
| 78 | |
| 79 Headers* Headers::create(ExceptionState&) | |
| 80 { | |
| 81 return create(); | |
| 82 } | |
| 83 | |
| 84 Headers* Headers::create(const Headers* init, ExceptionState& exceptionState) | |
| 85 { | |
| 86 // "The Headers(|init|) constructor, when invoked, must run these steps:" | |
| 87 // "1. Let |headers| be a new Headers object." | |
| 88 Headers* headers = create(); | |
| 89 // "2. If |init| is given, fill headers with |init|. Rethrow any exception." | |
| 90 headers->fillWith(init, exceptionState); | |
| 91 // "3. Return |headers|." | |
| 92 return headers; | |
| 93 } | |
| 94 | |
| 95 Headers* Headers::create(const Vector<Vector<String> >& init, ExceptionState& ex
ceptionState) | |
| 96 { | |
| 97 // The same steps as above. | |
| 98 Headers* headers = create(); | |
| 99 headers->fillWith(init, exceptionState); | |
| 100 return headers; | |
| 101 } | |
| 102 | |
| 103 Headers* Headers::create(const Dictionary& init, ExceptionState& exceptionState) | |
| 104 { | |
| 105 // "The Headers(|init|) constructor, when invoked, must run these steps:" | |
| 106 // "1. Let |headers| be a new Headers object." | |
| 107 Headers* headers = create(); | |
| 108 // "2. If |init| is given, fill headers with |init|. Rethrow any exception." | |
| 109 headers->fillWith(init, exceptionState); | |
| 110 // "3. Return |headers|." | |
| 111 return headers; | |
| 112 } | |
| 113 | |
| 114 Headers* Headers::create(FetchHeaderList* headerList) | |
| 115 { | |
| 116 return new Headers(headerList); | |
| 117 } | |
| 118 | |
| 119 Headers* Headers::createCopy() const | |
| 120 { | |
| 121 FetchHeaderList* headerList = m_headerList->createCopy(); | |
| 122 Headers* headers = create(headerList); | |
| 123 headers->m_guard = m_guard; | |
| 124 return headers; | |
| 125 } | |
| 126 | |
| 127 void Headers::append(const String& name, const String& value, ExceptionState& ex
ceptionState) | |
| 128 { | |
| 129 // "To append a name/value (|name|/|value|) pair to a Headers object | |
| 130 // (|headers|), run these steps:" | |
| 131 // "1. If |name| is not a name or |value| is not a value, throw a | |
| 132 // TypeError." | |
| 133 if (!FetchHeaderList::isValidHeaderName(name)) { | |
| 134 exceptionState.throwTypeError("Invalid name"); | |
| 135 return; | |
| 136 } | |
| 137 if (!FetchHeaderList::isValidHeaderValue(value)) { | |
| 138 exceptionState.throwTypeError("Invalid value"); | |
| 139 return; | |
| 140 } | |
| 141 // "2. If guard is |request|, throw a TypeError." | |
| 142 if (m_guard == ImmutableGuard) { | |
| 143 exceptionState.throwTypeError("Headers are immutable"); | |
| 144 return; | |
| 145 } | |
| 146 // "3. Otherwise, if guard is |request| and |name| is a forbidden header | |
| 147 // name, return." | |
| 148 if (m_guard == RequestGuard && FetchUtils::isForbiddenHeaderName(name)) | |
| 149 return; | |
| 150 // "4. Otherwise, if guard is |request-no-CORS| and |name|/|value| is not a | |
| 151 // simple header, return." | |
| 152 if (m_guard == RequestNoCORSGuard && !FetchUtils::isSimpleHeader(AtomicStrin
g(name), AtomicString(value))) | |
| 153 return; | |
| 154 // "5. Otherwise, if guard is |response| and |name| is a forbidden response | |
| 155 // header name, return." | |
| 156 if (m_guard == ResponseGuard && FetchUtils::isForbiddenResponseHeaderName(na
me)) | |
| 157 return; | |
| 158 // "6. Append |name|/|value| to header list." | |
| 159 m_headerList->append(name, value); | |
| 160 } | |
| 161 | |
| 162 void Headers::remove(const String& name, ExceptionState& exceptionState) | |
| 163 { | |
| 164 // "The delete(|name|) method, when invoked, must run these steps:" | |
| 165 // "1. If name is not a name, throw a TypeError." | |
| 166 if (!FetchHeaderList::isValidHeaderName(name)) { | |
| 167 exceptionState.throwTypeError("Invalid name"); | |
| 168 return; | |
| 169 } | |
| 170 // "2. If guard is |immutable|, throw a TypeError." | |
| 171 if (m_guard == ImmutableGuard) { | |
| 172 exceptionState.throwTypeError("Headers are immutable"); | |
| 173 return; | |
| 174 } | |
| 175 // "3. Otherwise, if guard is |request| and |name| is a forbidden header | |
| 176 // name, return." | |
| 177 if (m_guard == RequestGuard && FetchUtils::isForbiddenHeaderName(name)) | |
| 178 return; | |
| 179 // "4. Otherwise, if guard is |request-no-CORS| and |name|/`invalid` is not | |
| 180 // a simple header, return." | |
| 181 if (m_guard == RequestNoCORSGuard && !FetchUtils::isSimpleHeader(AtomicStrin
g(name), "invalid")) | |
| 182 return; | |
| 183 // "5. Otherwise, if guard is |response| and |name| is a forbidden response | |
| 184 // header name, return." | |
| 185 if (m_guard == ResponseGuard && FetchUtils::isForbiddenResponseHeaderName(na
me)) | |
| 186 return; | |
| 187 // "6. Delete |name| from header list." | |
| 188 m_headerList->remove(name); | |
| 189 } | |
| 190 | |
| 191 String Headers::get(const String& name, ExceptionState& exceptionState) | |
| 192 { | |
| 193 // "The get(|name|) method, when invoked, must run these steps:" | |
| 194 // "1. If |name| is not a name, throw a TypeError." | |
| 195 if (!FetchHeaderList::isValidHeaderName(name)) { | |
| 196 exceptionState.throwTypeError("Invalid name"); | |
| 197 return String(); | |
| 198 } | |
| 199 // "2. Return the value of the first header in header list whose name is | |
| 200 // |name|, and null otherwise." | |
| 201 String result; | |
| 202 m_headerList->get(name, result); | |
| 203 return result; | |
| 204 } | |
| 205 | |
| 206 Vector<String> Headers::getAll(const String& name, ExceptionState& exceptionStat
e) | |
| 207 { | |
| 208 // "The getAll(|name|) method, when invoked, must run these steps:" | |
| 209 // "1. If |name| is not a name, throw a TypeError." | |
| 210 if (!FetchHeaderList::isValidHeaderName(name)) { | |
| 211 exceptionState.throwTypeError("Invalid name"); | |
| 212 return Vector<String>(); | |
| 213 } | |
| 214 // "2. Return the values of all headers in header list whose name is |name|, | |
| 215 // in list order, and the empty sequence otherwise." | |
| 216 Vector<String> result; | |
| 217 m_headerList->getAll(name, result); | |
| 218 return result; | |
| 219 } | |
| 220 | |
| 221 bool Headers::has(const String& name, ExceptionState& exceptionState) | |
| 222 { | |
| 223 // "The has(|name|) method, when invoked, must run these steps:" | |
| 224 // "1. If |name| is not a name, throw a TypeError." | |
| 225 if (!FetchHeaderList::isValidHeaderName(name)) { | |
| 226 exceptionState.throwTypeError("Invalid name"); | |
| 227 return false; | |
| 228 } | |
| 229 // "2. Return true if there is a header in header list whose name is |name|, | |
| 230 // and false otherwise." | |
| 231 return m_headerList->has(name); | |
| 232 } | |
| 233 | |
| 234 void Headers::set(const String& name, const String& value, ExceptionState& excep
tionState) | |
| 235 { | |
| 236 // "The set(|name|, |value|) method, when invoked, must run these steps:" | |
| 237 // "1. If |name| is not a name or |value| is not a value, throw a | |
| 238 // TypeError." | |
| 239 if (!FetchHeaderList::isValidHeaderName(name)) { | |
| 240 exceptionState.throwTypeError("Invalid name"); | |
| 241 return; | |
| 242 } | |
| 243 if (!FetchHeaderList::isValidHeaderValue(value)) { | |
| 244 exceptionState.throwTypeError("Invalid value"); | |
| 245 return; | |
| 246 } | |
| 247 // "2. If guard is |immutable|, throw a TypeError." | |
| 248 if (m_guard == ImmutableGuard) { | |
| 249 exceptionState.throwTypeError("Headers are immutable"); | |
| 250 return; | |
| 251 } | |
| 252 // "3. Otherwise, if guard is |request| and |name| is a forbidden header | |
| 253 // name, return." | |
| 254 if (m_guard == RequestGuard && FetchUtils::isForbiddenHeaderName(name)) | |
| 255 return; | |
| 256 // "4. Otherwise, if guard is |request-no-CORS| and |name|/|value| is not a | |
| 257 // simple header, return." | |
| 258 if (m_guard == RequestNoCORSGuard && !FetchUtils::isSimpleHeader(AtomicStrin
g(name), AtomicString(value))) | |
| 259 return; | |
| 260 // "5. Otherwise, if guard is |response| and |name| is a forbidden response | |
| 261 // header name, return." | |
| 262 if (m_guard == ResponseGuard && FetchUtils::isForbiddenResponseHeaderName(na
me)) | |
| 263 return; | |
| 264 // "6. Set |name|/|value| in header list." | |
| 265 m_headerList->set(name, value); | |
| 266 } | |
| 267 | |
| 268 void Headers::fillWith(const Headers* object, ExceptionState& exceptionState) | |
| 269 { | |
| 270 ASSERT(m_headerList->size() == 0); | |
| 271 // "To fill a Headers object (|this|) with a given object (|object|), run | |
| 272 // these steps:" | |
| 273 // "1. If |object| is a Headers object, copy its header list as | |
| 274 // |headerListCopy| and then for each |header| in |headerListCopy|, | |
| 275 // retaining order, append header's |name|/|header|'s value to | |
| 276 // |headers|. Rethrow any exception." | |
| 277 for (size_t i = 0; i < object->m_headerList->list().size(); ++i) { | |
| 278 append(object->m_headerList->list()[i]->first, object->m_headerList->lis
t()[i]->second, exceptionState); | |
| 279 if (exceptionState.hadException()) | |
| 280 return; | |
| 281 } | |
| 282 } | |
| 283 | |
| 284 void Headers::fillWith(const Vector<Vector<String> >& object, ExceptionState& ex
ceptionState) | |
| 285 { | |
| 286 ASSERT(!m_headerList->size()); | |
| 287 // "2. Otherwise, if |object| is a sequence, then for each |header| in | |
| 288 // |object|, run these substeps: | |
| 289 // 1. If |header| does not contain exactly two items, throw a | |
| 290 // TypeError. | |
| 291 // 2. Append |header|'s first item/|header|'s second item to | |
| 292 // |headers|. Rethrow any exception." | |
| 293 for (size_t i = 0; i < object.size(); ++i) { | |
| 294 if (object[i].size() != 2) { | |
| 295 exceptionState.throwTypeError("Invalid value"); | |
| 296 return; | |
| 297 } | |
| 298 append(object[i][0], object[i][1], exceptionState); | |
| 299 if (exceptionState.hadException()) | |
| 300 return; | |
| 301 } | |
| 302 } | |
| 303 | |
| 304 void Headers::fillWith(const Dictionary& object, ExceptionState& exceptionState) | |
| 305 { | |
| 306 ASSERT(!m_headerList->size()); | |
| 307 Vector<String> keys; | |
| 308 object.getPropertyNames(keys); | |
| 309 if (!keys.size()) | |
| 310 return; | |
| 311 | |
| 312 // "3. Otherwise, if |object| is an open-ended dictionary, then for each | |
| 313 // |header| in object, run these substeps: | |
| 314 // 1. Set |header|'s key to |header|'s key, converted to ByteString. | |
| 315 // Rethrow any exception. | |
| 316 // 2. Append |header|'s key/|header|'s value to |headers|. Rethrow any | |
| 317 // exception." | |
| 318 // FIXME: Support OpenEndedDictionary<ByteString>. | |
| 319 for (size_t i = 0; i < keys.size(); ++i) { | |
| 320 String value; | |
| 321 if (!DictionaryHelper::get(object, keys[i], value)) { | |
| 322 exceptionState.throwTypeError("Invalid value"); | |
| 323 return; | |
| 324 } | |
| 325 append(keys[i], value, exceptionState); | |
| 326 if (exceptionState.hadException()) | |
| 327 return; | |
| 328 } | |
| 329 } | |
| 330 | |
| 331 Headers::Headers() | |
| 332 : m_headerList(FetchHeaderList::create()) | |
| 333 , m_guard(NoneGuard) | |
| 334 { | |
| 335 } | |
| 336 | |
| 337 Headers::Headers(FetchHeaderList* headerList) | |
| 338 : m_headerList(headerList) | |
| 339 , m_guard(NoneGuard) | |
| 340 { | |
| 341 } | |
| 342 | |
| 343 Iterator* Headers::iterator(ScriptState*, ExceptionState&) | |
| 344 { | |
| 345 return new HeadersIterator(m_headerList, HeadersIterator::KeyValue); | |
| 346 } | |
| 347 | |
| 348 void Headers::trace(Visitor* visitor) | |
| 349 { | |
| 350 visitor->trace(m_headerList); | |
| 351 } | |
| 352 | |
| 353 } // namespace blink | |
| OLD | NEW |