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

Unified Diff: Source/modules/serviceworkers/Headers.cpp

Issue 358573002: [ServiceWorker] Implement Headers class. (Closed) Base URL: https://chromium.googlesource.com/chromium/blink.git@master
Patch Set: rebase Created 6 years, 6 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 side-by-side diff with in-line comments
Download patch
« no previous file with comments | « Source/modules/serviceworkers/Headers.h ('k') | Source/modules/serviceworkers/Headers.idl » ('j') | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
Index: Source/modules/serviceworkers/Headers.cpp
diff --git a/Source/modules/serviceworkers/Headers.cpp b/Source/modules/serviceworkers/Headers.cpp
new file mode 100644
index 0000000000000000000000000000000000000000..2cf5213a6229f4ce5fb478815fa08be08f62f6fc
--- /dev/null
+++ b/Source/modules/serviceworkers/Headers.cpp
@@ -0,0 +1,320 @@
+// Copyright 2014 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "config.h"
+#include "modules/serviceworkers/Headers.h"
+
+#include "bindings/v8/Dictionary.h"
+#include "bindings/v8/ExceptionState.h"
+#include "core/fetch/CrossOriginAccessControl.h"
+#include "core/xml/XMLHttpRequest.h"
+#include "modules/serviceworkers/HeadersForEachCallback.h"
+#include "wtf/NotFound.h"
+#include "wtf/PassRefPtr.h"
+#include "wtf/RefPtr.h"
+#include "wtf/text/WTFString.h"
+
+namespace WebCore {
+
+PassRefPtr<Headers> Headers::create()
+{
+ return adoptRef(new Headers);
+}
+
+PassRefPtr<Headers> Headers::create(ExceptionState&)
+{
+ return create();
+}
+
+PassRefPtr<Headers> Headers::create(const Headers* init, ExceptionState& exceptionState)
+{
+ // "The Headers(|init|) constructor, when invoked, must run these steps:"
+ // "1. Let |headers| be a new Headers object."
+ RefPtr<Headers> headers = create();
+ // "2. If |init| is given, fill headers with |init|. Rethrow any exception."
+ headers->fillWith(init, exceptionState);
+ // "3. Return |headers|."
+ return headers.release();
+}
+
+PassRefPtr<Headers> Headers::create(const Dictionary& init, ExceptionState& exceptionState)
+{
+ // "The Headers(|init|) constructor, when invoked, must run these steps:"
+ // "1. Let |headers| be a new Headers object."
+ RefPtr<Headers> headers = create();
+ // "2. If |init| is given, fill headers with |init|. Rethrow any exception."
+ headers->fillWith(init, exceptionState);
+ // "3. Return |headers|."
+ return headers.release();
+}
+
+// Called when creating Request.
+PassRefPtr<Headers> Headers::create(FetchHeaderList* headerList)
+{
+ return adoptRef(new Headers(headerList));
+}
+
+Headers::~Headers()
+{
+}
+
+unsigned long Headers::size() const
+{
+ return m_headerList->size();
+}
+
+void Headers::append(const String& name, const String& value, ExceptionState& exceptionState)
+{
+ // "To append a name/value (|name|/|value|) pair to a Headers object
+ // (|headers|), run these steps:"
+ // "1. If |name| is not a name or |value| is not a value, throw a
+ // TypeError."
+ if (!FetchHeaderList::isValidHeaderName(name)) {
+ exceptionState.throwTypeError("Invalid name");
+ return;
+ }
+ if (!FetchHeaderList::isValidHeaderValue(value)) {
+ exceptionState.throwTypeError("Invalid value");
+ return;
+ }
+ // "2. If guard is |request|, throw a TypeError."
+ if (m_guard == ImmutableGuard) {
+ exceptionState.throwTypeError("Headers are immutable");
+ return;
+ }
+ // "3. Otherwise, if guard is |request| and |name| is a forbidden header
+ // name, return."
+ if (m_guard == RequestGuard && FetchHeaderList::isForbiddenHeaderName(name))
+ return;
+ // "4. Otherwise, if guard is |request-no-CORS| and |name|/|value| is not a
+ // simple header, return."
+ if (m_guard == RequestNoCORSGuard && !FetchHeaderList::isSimpleHeader(name, value))
+ return;
+ // "5. Otherwise, if guard is |response| and |name| is a forbidden response
+ // header name, return."
+ if (m_guard == ResponseGuard && FetchHeaderList::isForbiddenResponseHeaderName(name))
+ return;
+ // "6. Append |name|/|value| to header list."
+ m_headerList->append(name, value);
+}
+
+void Headers::remove(const String& name, ExceptionState& exceptionState)
+{
+ // "The delete(|name|) method, when invoked, must run these steps:"
+ // "1. If name is not a name, throw a TypeError."
+ if (!FetchHeaderList::isValidHeaderName(name)) {
+ exceptionState.throwTypeError("Invalid name");
+ return;
+ }
+ // "2. If guard is |immutable|, throw a TypeError."
+ if (m_guard == ImmutableGuard) {
+ exceptionState.throwTypeError("Headers are immutable");
+ return;
+ }
+ // "3. Otherwise, if guard is |request| and |name| is a forbidden header
+ // name, return."
+ if (m_guard == RequestGuard && FetchHeaderList::isForbiddenHeaderName(name))
+ return;
+ // "4. Otherwise, if guard is |request-no-CORS| and |name|/`invalid` is not
+ // a simple header, return."
+ if (m_guard == RequestNoCORSGuard && !FetchHeaderList::isSimpleHeader(name, "invalid"))
+ return;
+ // "5. Otherwise, if guard is |response| and |name| is a forbidden response
+ // header name, return."
+ if (m_guard == ResponseGuard && FetchHeaderList::isForbiddenResponseHeaderName(name))
+ return;
+ // "6. Delete |name| from header list."
+ m_headerList->remove(name);
+}
+
+String Headers::get(const String& name, ExceptionState& exceptionState)
+{
+ // "The get(|name|) method, when invoked, must run these steps:"
+ // "1. If |name| is not a name, throw a TypeError."
+ if (!FetchHeaderList::isValidHeaderName(name)) {
+ exceptionState.throwTypeError("Invalid name");
+ return String();
+ }
+ // "2. Return the value of the first header in header list whose name is
+ // |name|, and null otherwise."
+ String result;
+ m_headerList->get(name, result);
+ return result;
+}
+
+Vector<String> Headers::getAll(const String& name, ExceptionState& exceptionState)
+{
+ // "The getAll(|name|) method, when invoked, must run these steps:"
+ // "1. If |name| is not a name, throw a TypeError."
+ if (!FetchHeaderList::isValidHeaderName(name)) {
+ exceptionState.throwTypeError("Invalid name");
+ return Vector<String>();
+ }
+ // "2. Return the values of all headers in header list whose name is |name|,
+ // in list order, and the empty sequence otherwise."
+ Vector<String> result;
+ m_headerList->getAll(name, result);
+ return result;
+}
+
+bool Headers::has(const String& name, ExceptionState& exceptionState)
+{
+ // "The has(|name|) method, when invoked, must run these steps:"
+ // "1. If |name| is not a name, throw a TypeError."
+ if (!FetchHeaderList::isValidHeaderName(name)) {
+ exceptionState.throwTypeError("Invalid name");
+ return false;
+ }
+ // "2. Return true if there is a header in header list whose name is |name|,
+ // and false otherwise."
+ return m_headerList->has(name);
+}
+
+void Headers::set(const String& name, const String& value, ExceptionState& exceptionState)
+{
+ // "The set(|name|, |value|) method, when invoked, must run these steps:"
+ // "1. If |name| is not a name or |value| is not a value, throw a
+ // TypeError."
+ if (!FetchHeaderList::isValidHeaderName(name)) {
+ exceptionState.throwTypeError("Invalid name");
+ return;
+ }
+ if (!FetchHeaderList::isValidHeaderValue(value)) {
+ exceptionState.throwTypeError("Invalid value");
+ return;
+ }
+ // "2. If guard is |immutable|, throw a TypeError."
+ if (m_guard == ImmutableGuard) {
+ exceptionState.throwTypeError("Headers are immutable");
+ return;
+ }
+ // "3. Otherwise, if guard is |request| and |name| is a forbidden header
+ // name, return."
+ if (m_guard == RequestGuard && FetchHeaderList::isForbiddenHeaderName(name))
+ return;
+ // "4. Otherwise, if guard is |request-no-CORS| and |name|/|value| is not a
+ // simple header, return."
+ if (m_guard == RequestNoCORSGuard && !FetchHeaderList::isSimpleHeader(name, value))
+ return;
+ // "5. Otherwise, if guard is |response| and |name| is a forbidden response
+ // header name, return."
+ if (m_guard == ResponseGuard && FetchHeaderList::isForbiddenResponseHeaderName(name))
+ return;
+ // "6. Set |name|/|value| in header list."
+ m_headerList->set(name, value);
+}
+
+void Headers::forEach(PassOwnPtr<HeadersForEachCallback> callback, ScriptValue& thisArg)
+{
+ forEachInternal(callback, &thisArg);
+}
+
+void Headers::forEach(PassOwnPtr<HeadersForEachCallback> callback)
+{
+ forEachInternal(callback, 0);
+}
+
+void Headers::fillWith(const Headers* object, ExceptionState& exceptionState)
+{
+ ASSERT(m_headerList->size() == 0);
+ // "To fill a Headers object (|this|) with a given object (|object|), run
+ // these steps:"
+ // "1. If |object| is a Headers object, copy its header list as
+ // |headerListCopy| and then for each |header| in |headerListCopy|,
+ // retaining order, append header's |name|/|header|'s value to
+ // |headers|. Rethrow any exception."
+ for (size_t i = 0; i < object->m_headerList->list().size(); ++i) {
+ append(object->m_headerList->list()[i]->first, object->m_headerList->list()[i]->second, exceptionState);
+ if (exceptionState.hadException())
+ return;
+ }
+}
+
+void Headers::fillWith(const Dictionary& object, ExceptionState& exceptionState)
+{
+ ASSERT(m_headerList->size() == 0);
+ Vector<String> keys;
+ object.getOwnPropertyNames(keys);
+ if (keys.size() == 0)
+ return;
+
+ // Because of the restrictions in IDL compiler of blink we recieve
+ // sequence<sequence<ByteString>> as a Dictionary, which is a type of union
+ // type of HeadersInit defined in the spec.
+ // http://fetch.spec.whatwg.org/#headers-class
+ // FIXME: Support sequence<sequence<ByteString>>.
+ Vector<String> keyValuePair;
+ if (object.get(keys[0], keyValuePair)) {
+ // "2. Otherwise, if |object| is a sequence, then for each |header| in
+ // |object|, run these substeps:
+ // 1. If |header| does not contain two items, throw a TypeError.
+ // 2. Append |header|'s first item/|header|'s second item to
+ // |headers|. Rethrow any exception."
+ for (size_t i = 0; i < keys.size(); ++i) {
+ // We've already got the keyValuePair for key[0].
+ if (i > 0) {
+ if (!object.get(keys[i], keyValuePair)) {
+ exceptionState.throwTypeError("Invalid value");
+ return;
+ }
+ }
+ if (keyValuePair.size() < 2) {
+ exceptionState.throwTypeError("Invalid value");
+ return;
+ }
+ append(keyValuePair[0], keyValuePair[1], exceptionState);
+ if (exceptionState.hadException())
+ return;
+ keyValuePair.clear();
+ }
+ return;
+ }
+ // "3. Otherwise, if |object| is an open-ended dictionary, then for each
+ // |header| in object, run these substeps:
+ // 1. Set |header|'s key to |header|'s key, converted to ByteString.
+ // Rethrow any exception.
+ // 2. Append |header|'s key/|header|'s value to |headers|. Rethrow any
+ // exception."
+ // FIXME: Support OpenEndedDictionary<ByteString>.
+ for (size_t i = 0; i < keys.size(); ++i) {
+ String value;
+ if (!object.get(keys[i], value)) {
+ exceptionState.throwTypeError("Invalid value");
+ return;
+ }
+ append(keys[i], value, exceptionState);
+ if (exceptionState.hadException())
+ return;
+ }
+}
+
+Headers::Headers()
+ : m_headerList(FetchHeaderList::create())
+ , m_guard(NoneGuard)
+{
+ ScriptWrappable::init(this);
+}
+
+// Called when creating Request or Responce.
+Headers::Headers(FetchHeaderList* headerList)
+ : m_headerList(headerList)
+ , m_guard(NoneGuard)
+{
+ ScriptWrappable::init(this);
+}
+
+void Headers::forEachInternal(PassOwnPtr<HeadersForEachCallback> callback, ScriptValue* thisArg)
+{
+ TrackExceptionState exceptionState;
+ for (size_t i = 0; i < m_headerList->size(); ++i) {
+ if (thisArg)
+ callback->handleItem(*thisArg, m_headerList->list()[i]->second, m_headerList->list()[i]->first, this);
+ else
+ callback->handleItem(m_headerList->list()[i]->second, m_headerList->list()[i]->first, this);
+ if (exceptionState.hadException())
+ break;
+ }
+}
+
+} // namespace WebCore
« no previous file with comments | « Source/modules/serviceworkers/Headers.h ('k') | Source/modules/serviceworkers/Headers.idl » ('j') | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698