void XMLHttpRequest::makeSimpleCrossOriginAccessRequest(ExceptionCode& ec) { ASSERT(isSimpleCrossOriginAccessRequest(m_method, m_requestHeaders)); // Cross-origin requests are only defined for HTTP. We would catch this when checking response headers later, but there is no reason to send a request that's guaranteed to be denied. if (!m_url.protocolInHTTPFamily()) { ec = XMLHttpRequestException::NETWORK_ERR; networkError(); return; } KURL url = m_url; url.setUser(String()); url.setPass(String()); ResourceRequest request(url); request.setHTTPMethod(m_method); request.setAllowHTTPCookies(m_includeCredentials); request.setHTTPOrigin(scriptExecutionContext()->securityOrigin()->toString()); if (m_requestHeaders.size() > 0) request.addHTTPHeaderFields(m_requestHeaders); if (m_requestEntityBody) { ASSERT(m_method != "GET"); ASSERT(m_method != "HEAD"); request.setHTTPBody(m_requestEntityBody.release()); } if (m_async) loadRequestAsynchronously(request); else loadRequestSynchronously(request, ec); }
void XMLHttpRequest::makeCrossOriginAccessRequest(ExceptionCode& ec) { ASSERT(!m_sameOriginRequest); if (!m_uploadEventsAllowed && isSimpleCrossOriginAccessRequest(m_method, m_requestHeaders)) makeSimpleCrossOriginAccessRequest(ec); else makeCrossOriginAccessRequestWithPreflight(ec); }
void DocumentThreadableLoader::makeSimpleCrossOriginAccessRequest(const ResourceRequest& request) { ASSERT(m_options.preflightPolicy != ForcePreflight); ASSERT(m_options.preflightPolicy == PreventPreflight || isSimpleCrossOriginAccessRequest(request.httpMethod(), request.httpHeaderFields())); // Cross-origin requests are only allowed for HTTP and registered schemes. We would catch this when checking response headers later, but there is no reason to send a request that's guaranteed to be denied. if (!SchemeRegistry::shouldTreatURLSchemeAsCORSEnabled(request.url().protocol())) { m_client->didFailAccessControlCheck(ResourceError(errorDomainWebKitInternal, 0, request.url(), "Cross origin requests are only supported for HTTP.")); return; } loadRequest(request, DoSecurityCheck); }
void DocumentThreadableLoader::makeSimpleCrossOriginAccessRequest(const ResourceRequest& request) { ASSERT(isSimpleCrossOriginAccessRequest(request.httpMethod(), request.httpHeaderFields())); // Cross-origin requests are only defined for HTTP. We would catch this when checking response headers later, but there is no reason to send a request that's guaranteed to be denied. // FIXME: Consider allowing simple CORS requests to non-HTTP URLs. if (!request.url().protocolInHTTPFamily()) { m_client->didFail(ResourceError(errorDomainWebKitInternal, 0, request.url().string(), "Cross origin requests are only supported for HTTP.")); return; } loadRequest(request, DoSecurityCheck); }
void DocumentThreadableLoader::makeSimpleCrossOriginAccessRequest(const ResourceRequest& request) { ASSERT(isSimpleCrossOriginAccessRequest(request.httpMethod(), request.httpHeaderFields())); // Cross-origin requests are only defined for HTTP. We would catch this when checking response headers later, but there is no reason to send a request that's guaranteed to be denied. if (!request.url().protocolInHTTPFamily()) { m_client->didFail(ResourceError()); return; } // Make a copy of the passed request so that we can modify some details. ResourceRequest crossOriginRequest(request); crossOriginRequest.setHTTPOrigin(m_document->securityOrigin()->toString()); loadRequest(crossOriginRequest, DoSecurityCheck); }
void DocumentThreadableLoader::makeCrossOriginAccessRequest(const ResourceRequest& request) { ASSERT(m_options.crossOriginRequestPolicy == UseAccessControl); auto crossOriginRequest = std::make_unique<ResourceRequest>(request); updateRequestForAccessControl(*crossOriginRequest, securityOrigin(), m_options.allowCredentials()); if ((m_options.preflightPolicy == ConsiderPreflight && isSimpleCrossOriginAccessRequest(crossOriginRequest->httpMethod(), crossOriginRequest->httpHeaderFields())) || m_options.preflightPolicy == PreventPreflight) makeSimpleCrossOriginAccessRequest(*crossOriginRequest); else { m_simpleRequest = false; m_actualRequest = WTFMove(crossOriginRequest); if (CrossOriginPreflightResultCache::singleton().canSkipPreflight(securityOrigin()->toString(), m_actualRequest->url(), m_options.allowCredentials(), m_actualRequest->httpMethod(), m_actualRequest->httpHeaderFields())) preflightSuccess(); else makeCrossOriginAccessRequestWithPreflight(*m_actualRequest); } }
DocumentThreadableLoader::DocumentThreadableLoader(Document* document, ThreadableLoaderClient* client, BlockingBehavior blockingBehavior, const ResourceRequest& request, const ThreadableLoaderOptions& options) : m_client(client) , m_document(document) , m_options(options) #if PLATFORM(APOLLO) , m_sameOriginRequest(document->securityOrigin()->canRequestExt(request.url(), document)) #else , m_sameOriginRequest(document->securityOrigin()->canRequest(request.url())) #endif , m_async(blockingBehavior == LoadAsynchronously) { ASSERT(document); ASSERT(client); if (m_sameOriginRequest || m_options.crossOriginRequestPolicy == AllowCrossOriginRequests) { loadRequest(request, DoSecurityCheck); return; } if (m_options.crossOriginRequestPolicy == DenyCrossOriginRequests) { m_client->didFail(ResourceError()); return; } ASSERT(m_options.crossOriginRequestPolicy == UseAccessControl); OwnPtr<ResourceRequest> crossOriginRequest(new ResourceRequest(request)); crossOriginRequest->removeCredentials(); crossOriginRequest->setAllowCookies(m_options.allowCredentials); if (!m_options.forcePreflight && isSimpleCrossOriginAccessRequest(crossOriginRequest->httpMethod(), crossOriginRequest->httpHeaderFields())) makeSimpleCrossOriginAccessRequest(*crossOriginRequest); else { m_actualRequest.set(crossOriginRequest.release()); if (CrossOriginPreflightResultCache::shared().canSkipPreflight(document->securityOrigin()->toString(), m_actualRequest->url(), m_options.allowCredentials, m_actualRequest->httpMethod(), m_actualRequest->httpHeaderFields())) preflightSuccess(); else makeCrossOriginAccessRequestWithPreflight(*m_actualRequest); } }
DocumentThreadableLoader::DocumentThreadableLoader(Document* document, ThreadableLoaderClient* client, BlockingBehavior blockingBehavior, const ResourceRequest& request, const ThreadableLoaderOptions& options) : m_client(client) , m_document(document) , m_options(options) , m_sameOriginRequest(securityOrigin()->canRequest(request.url())) , m_async(blockingBehavior == LoadAsynchronously) #if ENABLE(INSPECTOR) , m_preflightRequestIdentifier(0) #endif { ASSERT(document); ASSERT(client); // Setting an outgoing referer is only supported in the async code path. ASSERT(m_async || request.httpReferrer().isEmpty()); if (m_sameOriginRequest || m_options.crossOriginRequestPolicy == AllowCrossOriginRequests) { loadRequest(request, DoSecurityCheck); return; } if (m_options.crossOriginRequestPolicy == DenyCrossOriginRequests) { m_client->didFail(ResourceError(errorDomainWebKitInternal, 0, request.url().string(), "Cross origin requests are not supported.")); return; } ASSERT(m_options.crossOriginRequestPolicy == UseAccessControl); OwnPtr<ResourceRequest> crossOriginRequest = adoptPtr(new ResourceRequest(request)); updateRequestForAccessControl(*crossOriginRequest, securityOrigin(), m_options.allowCredentials); if ((m_options.preflightPolicy == ConsiderPreflight && isSimpleCrossOriginAccessRequest(crossOriginRequest->httpMethod(), crossOriginRequest->httpHeaderFields())) || m_options.preflightPolicy == PreventPreflight) makeSimpleCrossOriginAccessRequest(*crossOriginRequest); else { m_actualRequest = crossOriginRequest.release(); if (CrossOriginPreflightResultCache::shared().canSkipPreflight(securityOrigin()->toString(), m_actualRequest->url(), m_options.allowCredentials, m_actualRequest->httpMethod(), m_actualRequest->httpHeaderFields())) preflightSuccess(); else makeCrossOriginAccessRequestWithPreflight(*m_actualRequest); } }
void DocumentThreadableLoader::makeCrossOriginAccessRequest(const ResourceRequest& request) { ASSERT(m_options.crossOriginRequestPolicy == UseAccessControl); OwnPtr<ResourceRequest> crossOriginRequest = adoptPtr(new ResourceRequest(request)); if ((m_options.preflightPolicy == ConsiderPreflight && isSimpleCrossOriginAccessRequest(crossOriginRequest->httpMethod(), crossOriginRequest->httpHeaderFields())) || m_options.preflightPolicy == PreventPreflight) { updateRequestForAccessControl(*crossOriginRequest, securityOrigin(), m_options.allowCredentials); makeSimpleCrossOriginAccessRequest(*crossOriginRequest); } else { m_simpleRequest = false; // Do not set the Origin header for preflight requests. updateRequestForAccessControl(*crossOriginRequest, 0, m_options.allowCredentials); m_actualRequest = crossOriginRequest.release(); if (CrossOriginPreflightResultCache::shared().canSkipPreflight(securityOrigin()->toString(), m_actualRequest->url(), m_options.allowCredentials, m_actualRequest->httpMethod(), m_actualRequest->httpHeaderFields())) preflightSuccess(); else makeCrossOriginAccessRequestWithPreflight(*m_actualRequest); } }
void XMLHttpRequest::createRequest(ExceptionCode& ec) { #if ENABLE(BLOB) // Only GET request is supported for blob URL. if (m_url.protocolIs("blob") && m_method != "GET") { ec = XMLHttpRequestException::NETWORK_ERR; return; } #endif // The presence of upload event listeners forces us to use preflighting because POSTing to an URL that does not // permit cross origin requests should look exactly like POSTing to an URL that does not respond at all. // Also, only async requests support upload progress events. bool uploadEvents = false; if (m_async) { m_progressEventThrottle.dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().loadstartEvent)); if (m_requestEntityBody && m_upload) { uploadEvents = m_upload->hasEventListeners(); m_upload->dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().loadstartEvent)); } } m_sameOriginRequest = securityOrigin()->canRequest(m_url); // We also remember whether upload events should be allowed for this request in case the upload listeners are // added after the request is started. m_uploadEventsAllowed = m_sameOriginRequest || uploadEvents || !isSimpleCrossOriginAccessRequest(m_method, m_requestHeaders); ResourceRequest request(m_url); request.setHTTPMethod(m_method); #if PLATFORM(CHROMIUM) request.setTargetType(ResourceRequest::TargetIsXHR); #endif if (m_requestEntityBody) { ASSERT(m_method != "GET"); ASSERT(m_method != "HEAD"); request.setHTTPBody(m_requestEntityBody.release()); } if (m_requestHeaders.size() > 0) request.addHTTPHeaderFields(m_requestHeaders); ThreadableLoaderOptions options; options.sendLoadCallbacks = SendCallbacks; options.sniffContent = DoNotSniffContent; options.preflightPolicy = uploadEvents ? ForcePreflight : ConsiderPreflight; options.allowCredentials = (m_sameOriginRequest || m_includeCredentials) ? AllowStoredCredentials : DoNotAllowStoredCredentials; options.crossOriginRequestPolicy = UseAccessControl; options.securityOrigin = securityOrigin(); m_exceptionCode = 0; m_error = false; if (m_async) { if (m_upload) request.setReportUploadProgress(true); // ThreadableLoader::create can return null here, for example if we're no longer attached to a page. // This is true while running onunload handlers. // FIXME: Maybe we need to be able to send XMLHttpRequests from onunload, <http://bugs.webkit.org/show_bug.cgi?id=10904>. // FIXME: Maybe create() can return null for other reasons too? m_loader = ThreadableLoader::create(scriptExecutionContext(), this, request, options); if (m_loader) { // Neither this object nor the JavaScript wrapper should be deleted while // a request is in progress because we need to keep the listeners alive, // and they are referenced by the JavaScript wrapper. setPendingActivity(this); } } else { InspectorInstrumentation::willLoadXHRSynchronously(scriptExecutionContext()); ThreadableLoader::loadResourceSynchronously(scriptExecutionContext(), request, *this, options); InspectorInstrumentation::didLoadXHRSynchronously(scriptExecutionContext()); } if (!m_exceptionCode && m_error) m_exceptionCode = XMLHttpRequestException::NETWORK_ERR; ec = m_exceptionCode; }
void XMLHttpRequest::createRequest(ExceptionCode& ec) { #if ENABLE(BLOB) // Only GET request is supported for blob URL. if (m_url.protocolIs("blob") && m_method != "GET") { ec = XMLHttpRequestException::NETWORK_ERR; return; } #endif // The presence of upload event listeners forces us to use preflighting because POSTing to an URL that does not // permit cross origin requests should look exactly like POSTing to an URL that does not respond at all. // Also, only async requests support upload progress events. bool uploadEvents = false; if (m_async) { m_progressEventThrottle.dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().loadstartEvent)); if (m_requestEntityBody && m_upload) { uploadEvents = m_upload->hasEventListeners(); m_upload->dispatchEvent(XMLHttpRequestProgressEvent::create(eventNames().loadstartEvent)); } } m_sameOriginRequest = scriptExecutionContext()->securityOrigin()->canRequest(m_url); // We also remember whether upload events should be allowed for this request in case the upload listeners are // added after the request is started. m_uploadEventsAllowed = m_sameOriginRequest || uploadEvents || !isSimpleCrossOriginAccessRequest(m_method, m_requestHeaders); ResourceRequest request(m_url); request.setHTTPMethod(m_method); if (m_requestEntityBody) { ASSERT(m_method != "GET"); ASSERT(m_method != "HEAD"); request.setHTTPBody(m_requestEntityBody.release()); } if (m_requestHeaders.size() > 0) request.addHTTPHeaderFields(m_requestHeaders); #if PLATFORM(BLACKBERRY) request.setIsXMLHTTPRequest(true); #endif ThreadableLoaderOptions options; options.sendLoadCallbacks = true; options.sniffContent = false; options.forcePreflight = uploadEvents; options.allowCredentials = m_sameOriginRequest || m_includeCredentials; options.crossOriginRequestPolicy = UseAccessControl; #if PLATFORM(BLACKBERRY) // We may stay in worker thread in which script execution context // is not document. So check it first. if (scriptExecutionContext()->isDocument() && document()->settings() && !document()->settings()->shouldUseCrossOriginProtocolCheck()) options.enforceCrossOriginProtocolCheck = false; #endif m_exceptionCode = 0; m_error = false; if (m_async) { if (m_upload) request.setReportUploadProgress(true); // ThreadableLoader::create can return null here, for example if we're no longer attached to a page. // This is true while running onunload handlers. // FIXME: Maybe we need to be able to send XMLHttpRequests from onunload, <http://bugs.webkit.org/show_bug.cgi?id=10904>. // FIXME: Maybe create() can return null for other reasons too? m_loader = ThreadableLoader::create(scriptExecutionContext(), this, request, options); if (m_loader) { // Neither this object nor the JavaScript wrapper should be deleted while // a request is in progress because we need to keep the listeners alive, // and they are referenced by the JavaScript wrapper. setPendingActivity(this); // For now we should only balance the nonCached request count for main-thread XHRs and not // Worker XHRs, as the Cache is not thread-safe. // This will become irrelevant after https://bugs.webkit.org/show_bug.cgi?id=27165 is resolved. if (!scriptExecutionContext()->isWorkerContext()) { ASSERT(isMainThread()); ASSERT(!m_didTellLoaderAboutRequest); cache()->loader()->nonCacheRequestInFlight(m_url); m_didTellLoaderAboutRequest = true; } } } else ThreadableLoader::loadResourceSynchronously(scriptExecutionContext(), request, *this, options); if (!m_exceptionCode && m_error) m_exceptionCode = XMLHttpRequestException::NETWORK_ERR; ec = m_exceptionCode; }
void XMLHttpRequest::createRequest(ExceptionCode& ec) { // Only GET request is supported for blob URL. if (!m_async && m_url.protocolIsBlob() && m_method != "GET") { ec = NETWORK_ERR; return; } m_sendFlag = true; // The presence of upload event listeners forces us to use preflighting because POSTing to an URL that does not // permit cross origin requests should look exactly like POSTing to an URL that does not respond at all. // Also, only async requests support upload progress events. bool uploadEvents = false; if (m_async) { m_progressEventThrottle.dispatchProgressEvent(eventNames().loadstartEvent); if (m_requestEntityBody && m_upload) { uploadEvents = m_upload->hasEventListeners(); m_upload->dispatchProgressEvent(eventNames().loadstartEvent); } } m_sameOriginRequest = securityOrigin()->canRequest(m_url); // We also remember whether upload events should be allowed for this request in case the upload listeners are // added after the request is started. m_uploadEventsAllowed = m_sameOriginRequest || uploadEvents || !isSimpleCrossOriginAccessRequest(m_method, m_requestHeaders); ResourceRequest request(m_url); request.setRequester(ResourceRequest::Requester::XHR); request.setHTTPMethod(m_method); if (m_requestEntityBody) { ASSERT(m_method != "GET"); ASSERT(m_method != "HEAD"); request.setHTTPBody(WTFMove(m_requestEntityBody)); } if (!m_requestHeaders.isEmpty()) request.setHTTPHeaderFields(m_requestHeaders); ThreadableLoaderOptions options; options.setSendLoadCallbacks(SendCallbacks); options.setSniffContent(DoNotSniffContent); options.preflightPolicy = uploadEvents ? ForcePreflight : ConsiderPreflight; options.setAllowCredentials((m_sameOriginRequest || m_includeCredentials) ? AllowStoredCredentials : DoNotAllowStoredCredentials); options.setCredentialRequest(m_includeCredentials ? ClientRequestedCredentials : ClientDidNotRequestCredentials); options.crossOriginRequestPolicy = UseAccessControl; options.securityOrigin = securityOrigin(); options.contentSecurityPolicyEnforcement = scriptExecutionContext()->shouldBypassMainWorldContentSecurityPolicy() ? ContentSecurityPolicyEnforcement::DoNotEnforce : ContentSecurityPolicyEnforcement::EnforceConnectSrcDirective; options.initiator = cachedResourceRequestInitiators().xmlhttprequest; if (m_timeoutMilliseconds) { if (!m_async) request.setTimeoutInterval(m_timeoutMilliseconds / 1000.0); else { m_sendingTime = std::chrono::steady_clock::now(); m_timeoutTimer.startOneShot(std::chrono::milliseconds { m_timeoutMilliseconds }); } } m_exceptionCode = 0; m_error = false; if (m_async) { if (m_upload) request.setReportUploadProgress(true); // ThreadableLoader::create can return null here, for example if we're no longer attached to a page or if a content blocker blocks the load. // This is true while running onunload handlers. // FIXME: Maybe we need to be able to send XMLHttpRequests from onunload, <http://bugs.webkit.org/show_bug.cgi?id=10904>. m_loader = ThreadableLoader::create(scriptExecutionContext(), this, request, options); // Neither this object nor the JavaScript wrapper should be deleted while // a request is in progress because we need to keep the listeners alive, // and they are referenced by the JavaScript wrapper. setPendingActivity(this); if (!m_loader) { m_sendFlag = false; m_timeoutTimer.stop(); m_networkErrorTimer.startOneShot(0); } } else { InspectorInstrumentation::willLoadXHRSynchronously(scriptExecutionContext()); ThreadableLoader::loadResourceSynchronously(scriptExecutionContext(), request, *this, options); InspectorInstrumentation::didLoadXHRSynchronously(scriptExecutionContext()); } if (!m_exceptionCode && m_error) m_exceptionCode = NETWORK_ERR; ec = m_exceptionCode; }
void XMLHttpRequest::createRequest(ExceptionState& exceptionState) { // Only GET request is supported for blob URL. if (m_url.protocolIs("blob") && m_method != "GET") { exceptionState.throwDOMException(NetworkError, "'GET' is the only method allowed for 'blob:' URLs."); return; } // The presence of upload event listeners forces us to use preflighting because POSTing to an URL that does not // permit cross origin requests should look exactly like POSTing to an URL that does not respond at all. // Also, only async requests support upload progress events. bool uploadEvents = false; if (m_async) { m_progressEventThrottle.dispatchEvent(XMLHttpRequestProgressEvent::create(EventTypeNames::loadstart)); if (m_requestEntityBody && m_upload) { uploadEvents = m_upload->hasEventListeners(); m_upload->dispatchEvent(XMLHttpRequestProgressEvent::create(EventTypeNames::loadstart)); } } m_sameOriginRequest = securityOrigin()->canRequest(m_url); // We also remember whether upload events should be allowed for this request in case the upload listeners are // added after the request is started. m_uploadEventsAllowed = m_sameOriginRequest || uploadEvents || !isSimpleCrossOriginAccessRequest(m_method, m_requestHeaders); ResourceRequest request(m_url); request.setHTTPMethod(m_method); request.setTargetType(ResourceRequest::TargetIsXHR); // When "blob" is specified for the responseType attribute, // we redirect the downloaded data to a file-handle directly // and get the file-path as the result. if (responseTypeCode() == ResponseTypeBlob) request.setDownloadToFile(true); InspectorInstrumentation::willLoadXHR(executionContext(), this, this, m_method, m_url, m_async, m_requestEntityBody ? m_requestEntityBody->deepCopy() : 0, m_requestHeaders, m_includeCredentials); if (m_requestEntityBody) { ASSERT(m_method != "GET"); ASSERT(m_method != "HEAD"); request.setHTTPBody(m_requestEntityBody.release()); } if (m_requestHeaders.size() > 0) request.addHTTPHeaderFields(m_requestHeaders); ThreadableLoaderOptions options; options.sendLoadCallbacks = SendCallbacks; options.sniffContent = DoNotSniffContent; options.preflightPolicy = uploadEvents ? ForcePreflight : ConsiderPreflight; options.allowCredentials = (m_sameOriginRequest || m_includeCredentials) ? AllowStoredCredentials : DoNotAllowStoredCredentials; options.credentialsRequested = m_includeCredentials ? ClientRequestedCredentials : ClientDidNotRequestCredentials; options.crossOriginRequestPolicy = UseAccessControl; options.securityOrigin = securityOrigin(); options.initiator = FetchInitiatorTypeNames::xmlhttprequest; options.contentSecurityPolicyEnforcement = ContentSecurityPolicy::shouldBypassMainWorld(executionContext()) ? DoNotEnforceContentSecurityPolicy : EnforceConnectSrcDirective; // TODO(tsepez): Specify TreatAsActiveContent per http://crbug.com/305303. options.mixedContentBlockingTreatment = TreatAsPassiveContent; options.timeoutMilliseconds = m_timeoutMilliseconds; // Since we redirect the downloaded data to a file-handle directly // when "blob" is specified for the responseType attribute, // buffering is not needed. if (responseTypeCode() == ResponseTypeBlob) options.dataBufferingPolicy = DoNotBufferData; m_exceptionCode = 0; m_error = false; if (m_async) { if (m_upload) request.setReportUploadProgress(true); // ThreadableLoader::create can return null here, for example if we're no longer attached to a page. // This is true while running onunload handlers. // FIXME: Maybe we need to be able to send XMLHttpRequests from onunload, <http://bugs.webkit.org/show_bug.cgi?id=10904>. // FIXME: Maybe create() can return null for other reasons too? ASSERT(!m_loader); m_loader = ThreadableLoader::create(executionContext(), this, request, options); if (m_loader) { // Neither this object nor the JavaScript wrapper should be deleted while // a request is in progress because we need to keep the listeners alive, // and they are referenced by the JavaScript wrapper. setPendingActivity(this); } } else { ThreadableLoader::loadResourceSynchronously(executionContext(), request, *this, options); } if (!m_exceptionCode && m_error) m_exceptionCode = NetworkError; if (m_exceptionCode) exceptionState.throwUninformativeAndGenericDOMException(m_exceptionCode); }