diff options
author | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
---|---|---|
committer | Lorry Tar Creator <lorry-tar-importer@lorry> | 2017-06-27 06:07:23 +0000 |
commit | 1bf1084f2b10c3b47fd1a588d85d21ed0eb41d0c (patch) | |
tree | 46dcd36c86e7fbc6e5df36deb463b33e9967a6f7 /Source/WebCore/Modules/fetch/FetchRequest.cpp | |
parent | 32761a6cee1d0dee366b885b7b9c777e67885688 (diff) | |
download | WebKitGtk-tarball-master.tar.gz |
webkitgtk-2.16.5HEADwebkitgtk-2.16.5master
Diffstat (limited to 'Source/WebCore/Modules/fetch/FetchRequest.cpp')
-rw-r--r-- | Source/WebCore/Modules/fetch/FetchRequest.cpp | 241 |
1 files changed, 241 insertions, 0 deletions
diff --git a/Source/WebCore/Modules/fetch/FetchRequest.cpp b/Source/WebCore/Modules/fetch/FetchRequest.cpp new file mode 100644 index 000000000..b879a7bcc --- /dev/null +++ b/Source/WebCore/Modules/fetch/FetchRequest.cpp @@ -0,0 +1,241 @@ +/* + * Copyright (C) 2016 Canon Inc. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted, provided that the following conditions + * are required to be met: + * + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of Canon Inc. nor the names of + * its contributors may be used to endorse or promote products derived + * from this software without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY CANON INC. AND ITS CONTRIBUTORS "AS IS" AND ANY + * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED + * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE + * DISCLAIMED. IN NO EVENT SHALL CANON INC. AND ITS CONTRIBUTORS BE LIABLE FOR + * ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER + * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, + * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE + * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + */ + +#include "config.h" +#include "FetchRequest.h" + +#if ENABLE(FETCH_API) + +#include "ExceptionCode.h" +#include "HTTPParsers.h" +#include "ScriptExecutionContext.h" +#include "SecurityOrigin.h" + +namespace WebCore { + +static std::optional<Exception> setMethod(ResourceRequest& request, const String& initMethod) +{ + if (!isValidHTTPToken(initMethod)) + return Exception { TypeError, ASCIILiteral("Method is not a valid HTTP token.") }; + + String method = initMethod.convertToASCIIUppercase(); + if (method == "CONNECT" || method == "TRACE" || method == "TRACK") + return Exception { TypeError, ASCIILiteral("Method is forbidden.") }; + + request.setHTTPMethod((method == "DELETE" || method == "GET" || method == "HEAD" || method == "OPTIONS" || method == "POST" || method == "PUT") ? method : initMethod); + + return std::nullopt; +} + +static std::optional<Exception> setReferrer(FetchRequest::InternalRequest& request, ScriptExecutionContext& context, const String& referrer) +{ + if (referrer.isEmpty()) { + request.referrer = ASCIILiteral("no-referrer"); + return std::nullopt; + } + // FIXME: Tighten the URL parsing algorithm according https://url.spec.whatwg.org/#concept-url-parser. + URL referrerURL = context.completeURL(referrer); + if (!referrerURL.isValid()) + return Exception { TypeError, ASCIILiteral("Referrer is not a valid URL.") }; + + if (referrerURL.protocolIs("about") && referrerURL.path() == "client") { + request.referrer = ASCIILiteral("client"); + return std::nullopt; + } + + if (!(context.securityOrigin() && context.securityOrigin()->canRequest(referrerURL))) + return Exception { TypeError, ASCIILiteral("Referrer is not same-origin.") }; + + request.referrer = referrerURL.string(); + return std::nullopt; +} + +static std::optional<Exception> buildOptions(FetchRequest::InternalRequest& request, ScriptExecutionContext& context, const FetchRequest::Init& init) +{ + if (!init.window.isUndefinedOrNull()) + return Exception { TypeError, ASCIILiteral("Window can only be null.") }; + + if (!init.referrer.isNull()) { + if (auto exception = setReferrer(request, context, init.referrer)) + return exception; + } + + if (init.referrerPolicy) + request.options.referrerPolicy = init.referrerPolicy.value(); + + if (init.mode) + request.options.mode = init.mode.value(); + if (request.options.mode == FetchOptions::Mode::Navigate) + return Exception { TypeError, ASCIILiteral("Request constructor does not accept navigate fetch mode.") }; + + if (init.credentials) + request.options.credentials = init.credentials.value(); + + if (init.cache) + request.options.cache = init.cache.value(); + if (request.options.cache == FetchOptions::Cache::OnlyIfCached && request.options.mode != FetchOptions::Mode::SameOrigin) + return Exception { TypeError, ASCIILiteral("only-if-cached cache option requires fetch mode to be same-origin.") }; + + if (init.redirect) + request.options.redirect = init.redirect.value(); + + if (!init.integrity.isNull()) + request.integrity = init.integrity; + + if (!init.method.isNull()) { + if (auto exception = setMethod(request.request, init.method)) + return exception; + } + + return std::nullopt; +} + +static bool methodCanHaveBody(const FetchRequest::InternalRequest& internalRequest) +{ + return internalRequest.request.httpMethod() != "GET" && internalRequest.request.httpMethod() != "HEAD"; +} + +ExceptionOr<FetchHeaders&> FetchRequest::initializeOptions(const Init& init) +{ + ASSERT(scriptExecutionContext()); + + auto exception = buildOptions(m_internalRequest, *scriptExecutionContext(), init); + if (exception) + return WTFMove(exception.value()); + + if (m_internalRequest.options.mode == FetchOptions::Mode::NoCors) { + const String& method = m_internalRequest.request.httpMethod(); + if (method != "GET" && method != "POST" && method != "HEAD") + return Exception { TypeError, ASCIILiteral("Method must be GET, POST or HEAD in no-cors mode.") }; + if (!m_internalRequest.integrity.isEmpty()) + return Exception { TypeError, ASCIILiteral("There cannot be an integrity in no-cors mode.") }; + m_headers->setGuard(FetchHeaders::Guard::RequestNoCors); + } + return m_headers.get(); +} + +ExceptionOr<FetchHeaders&> FetchRequest::initializeWith(const String& url, const Init& init) +{ + ASSERT(scriptExecutionContext()); + // FIXME: Tighten the URL parsing algorithm according https://url.spec.whatwg.org/#concept-url-parser. + URL requestURL = scriptExecutionContext()->completeURL(url); + if (!requestURL.isValid() || !requestURL.user().isEmpty() || !requestURL.pass().isEmpty()) + return Exception { TypeError, ASCIILiteral("URL is not valid or contains user credentials.") }; + + m_internalRequest.options.mode = Mode::Cors; + m_internalRequest.options.credentials = Credentials::Omit; + m_internalRequest.referrer = ASCIILiteral("client"); + m_internalRequest.request.setURL(requestURL); + m_internalRequest.request.setRequester(ResourceRequest::Requester::Fetch); + m_internalRequest.request.setInitiatorIdentifier(scriptExecutionContext()->resourceRequestIdentifier()); + + return initializeOptions(init); +} + +ExceptionOr<FetchHeaders&> FetchRequest::initializeWith(FetchRequest& input, const Init& init) +{ + if (input.isDisturbedOrLocked()) + return Exception {TypeError, ASCIILiteral("Request input is disturbed or locked.") }; + + m_internalRequest = input.m_internalRequest; + + return initializeOptions(init); +} + +ExceptionOr<void> FetchRequest::setBody(JSC::ExecState& execState, JSC::JSValue body, FetchRequest* request) +{ + if (!body.isNull()) { + if (!methodCanHaveBody(m_internalRequest)) + return Exception { TypeError }; + ASSERT(scriptExecutionContext()); + extractBody(*scriptExecutionContext(), execState, body); + if (isBodyNull()) + return Exception { TypeError }; + } else if (request && !request->isBodyNull()) { + if (!methodCanHaveBody(m_internalRequest)) + return Exception { TypeError }; + m_body = WTFMove(request->m_body); + request->setDisturbed(); + } + updateContentType(); + return { }; +} + +String FetchRequest::referrer() const +{ + if (m_internalRequest.referrer == "no-referrer") + return String(); + if (m_internalRequest.referrer == "client") + return ASCIILiteral("about:client"); + return m_internalRequest.referrer; +} + +const String& FetchRequest::url() const +{ + if (m_requestURL.isNull()) + m_requestURL = m_internalRequest.request.url().serialize(); + return m_requestURL; +} + +ResourceRequest FetchRequest::internalRequest() const +{ + ASSERT(scriptExecutionContext()); + + ResourceRequest request = m_internalRequest.request; + request.setHTTPHeaderFields(m_headers->internalHeaders()); + + if (!isBodyNull()) + request.setHTTPBody(body().bodyForInternalRequest(*scriptExecutionContext())); + + return request; +} + +ExceptionOr<Ref<FetchRequest>> FetchRequest::clone(ScriptExecutionContext& context) +{ + if (isDisturbedOrLocked()) + return Exception { TypeError }; + + auto clone = adoptRef(*new FetchRequest(context, std::nullopt, FetchHeaders::create(m_headers.get()), FetchRequest::InternalRequest(m_internalRequest))); + clone->cloneBody(*this); + return WTFMove(clone); +} + +const char* FetchRequest::activeDOMObjectName() const +{ + return "Request"; +} + +bool FetchRequest::canSuspendForDocumentSuspension() const +{ + // FIXME: We can probably do the same strategy as XHR. + return !isActive(); +} + +} // namespace WebCore + +#endif // ENABLE(FETCH_API) |