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

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: 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
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..52e4a88c4796a9358435dd64edee3cdfb6e2e25a
--- /dev/null
+++ b/Source/modules/serviceworkers/Headers.cpp
@@ -0,0 +1,319 @@
+// 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/FetchManager.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* input, 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(input, exceptionState);
+ // 3. Return headers.
+ return headers.release();
+}
+
+PassRefPtr<Headers> Headers::create(const Dictionary& input, 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(input, 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 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. 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/value 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. Remove all headers whose name is 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;
+ if (m_headerList->get(name, result))
+ return result;
+ return String();
+}
+
+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::clearHeaderList()
+{
+ m_headerList->clearList();
+}
+
+void Headers::fillWith(const Headers* headers, ExceptionState& exceptionState)
+{
yhirano 2014/06/26 07:22:13 Can this method be called when |this| is not empty
horo 2014/06/26 08:30:08 Added ASSERT(m_headerList->size() == 0);
+ // To fill a Headers object (headers) 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 < headers->list()->list().size(); ++i) {
+ append(headers->list()->list()[i]->first, headers->list()->list()[i]->second, exceptionState);
+ if (exceptionState.hadException())
+ return;
+ }
+}
+
+void Headers::fillWith(const Dictionary& dictionary, ExceptionState& exceptionState)
+{
yhirano 2014/06/26 07:22:13 ditto
horo 2014/06/26 08:30:08 Done.
+ Vector<String> keys;
+ dictionary.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 (dictionary.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 time to headers.
+ // Rethrow any exception.
+ for (size_t i = 0; i < keys.size(); ++i) {
+ if (i != 0 && !dictionary.get(keys[i], keyValuePair)) {
yhirano 2014/06/26 07:22:13 [optional] I would split these conditions. // We'
horo 2014/06/26 08:30:08 Done.
+ exceptionState.throwTypeError("Invalid value");
+ return;
+ }
+ if (keyValuePair.size() != 2) {
yhirano 2014/06/26 07:22:13 I'm not sure whether the spec says the size must b
horo 2014/06/26 08:30:08 Done.
+ 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 (!dictionary.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]->first, m_headerList->list()[i]->second, this);
+ else
+ callback->handleItem(m_headerList->list()[i]->first, m_headerList->list()[i]->second, this);
+ if (exceptionState.hadException())
+ break;
+ }
+}
+
+} // namespace WebCore

Powered by Google App Engine
This is Rietveld 408576698