void MainResourceLoader::didFinishLoading(double finishTime) { // There is a bug in CFNetwork where callbacks can be dispatched even when loads are deferred. // See <rdar://problem/6304600> for more details. #if !USE(CF) ASSERT(shouldLoadAsEmptyDocument(frameLoader()->activeDocumentLoader()->url()) || !defersLoading() || InspectorInstrumentation::isDebuggerPaused(m_frame.get())); #endif // The additional processing can do anything including possibly removing the last // reference to this object. RefPtr<MainResourceLoader> protect(this); RefPtr<DocumentLoader> dl = documentLoader(); #if PLATFORM(MAC) && !PLATFORM(IOS) && __MAC_OS_X_VERSION_MIN_REQUIRED >= 1080 if (m_filter) { int length; const char* data = wkFilterDataComplete(m_filter, &length); WebFilterEvaluator *filter = m_filter; // Remove this->m_filter early so didReceiveData doesn't see it. m_filter = 0; if (data) didReceiveData(data, length, -1, false); wkFilterRelease(filter); } #endif if (m_loadingMultipartContent) dl->maybeFinishLoadingMultipartContent(); documentLoader()->timing()->setResponseEnd(finishTime ? finishTime : (m_timeOfLastDataReceived ? m_timeOfLastDataReceived : monotonicallyIncreasingTime())); documentLoader()->finishedLoading(); ResourceLoader::didFinishLoading(finishTime); dl->applicationCacheHost()->finishedLoadingMainResource(); }
void DocumentThreadableLoader::loadRequest(const ResourceRequest& request, SecurityCheckPolicy securityCheck) { // Any credential should have been removed from the cross-site requests. const KURL& requestURL = request.url(); ASSERT(m_sameOriginRequest || requestURL.user().isEmpty()); ASSERT(m_sameOriginRequest || requestURL.pass().isEmpty()); if (m_async) { // Don't sniff content or send load callbacks for the preflight request. bool sendLoadCallbacks = m_options.sendLoadCallbacks && !m_actualRequest; bool sniffContent = m_options.sniffContent && !m_actualRequest; // Keep buffering the data for the preflight request. bool shouldBufferData = m_options.shouldBufferData || m_actualRequest; // Clear the loader so that any callbacks from SubresourceLoader::create will not have the old loader. m_loader = 0; m_loader = resourceLoadScheduler()->scheduleSubresourceLoad(m_document->frame(), this, request, ResourceLoadPriorityMedium, securityCheck, sendLoadCallbacks, sniffContent, m_optionalOutgoingReferrer, shouldBufferData); return; } // FIXME: ThreadableLoaderOptions.sniffContent is not supported for synchronous requests. StoredCredentials storedCredentials = m_options.allowCredentials ? AllowStoredCredentials : DoNotAllowStoredCredentials; Vector<char> data; ResourceError error; ResourceResponse response; unsigned long identifier = std::numeric_limits<unsigned long>::max(); if (m_document->frame()) identifier = m_document->frame()->loader()->loadResourceSynchronously(request, storedCredentials, error, response, data); // No exception for file:/// resources, see <rdar://problem/4962298>. // Also, if we have an HTTP response, then it wasn't a network error in fact. if (!error.isNull() && !requestURL.isLocalFile() && response.httpStatusCode() <= 0) { m_client->didFail(error); return; } // FIXME: FrameLoader::loadSynchronously() does not tell us whether a redirect happened or not, so we guess by comparing the // request and response URLs. This isn't a perfect test though, since a server can serve a redirect to the same URL that was // requested. Also comparing the request and response URLs as strings will fail if the requestURL still has its credentials. if (requestURL != response.url() && !isAllowedRedirect(response.url())) { m_client->didFailRedirectCheck(); return; } didReceiveResponse(0, response); const char* bytes = static_cast<const char*>(data.data()); int len = static_cast<int>(data.size()); didReceiveData(0, bytes, len); didFinishLoading(identifier, 0.0); }
void MultipartHandle::contentEnded() { // Process the leftover data. while (processContent()) { } if (m_state != End) { // It seems we are still not at the end of the processing. // Push out the remaining data. didReceiveData(m_buffer.size()); m_state = End; } m_buffer.clear(); }
void PluginStream::sendJavaScriptStream(const KURL& requestURL, const CString& resultString) { didReceiveResponse(0, ResourceResponse(requestURL, "text/plain", resultString.length(), "", "")); if (m_streamState == StreamStopped) return; if (!resultString.isNull()) { didReceiveData(0, resultString.data(), resultString.length()); if (m_streamState == StreamStopped) return; } m_loader = 0; destroyStream(resultString.isNull() ? NPRES_NETWORK_ERR : NPRES_DONE); }
void ResourceLoader::didReceiveData(ResourceHandle*, const char* data, int length, int lengthReceived) { #if ENABLE(INSPECTOR) if (InspectorTimelineAgent::instanceCount()) { InspectorTimelineAgent* timelineAgent = m_frame->page() ? m_frame->page()->inspectorTimelineAgent() : 0; if (timelineAgent) timelineAgent->willReceiveResourceData(identifier()); } #endif didReceiveData(data, length, lengthReceived, false); #if ENABLE(INSPECTOR) if (InspectorTimelineAgent::instanceCount()) { InspectorTimelineAgent* timelineAgent = m_frame->page() ? m_frame->page()->inspectorTimelineAgent() : 0; if (timelineAgent) timelineAgent->didReceiveResourceData(); } #endif }
void SubresourceLoader::didReceiveDataArray(CFArrayRef dataArray) { // Reference the object in this method since the additional processing can do // anything including removing the last reference to this object; one example of this is 3266216. RefPtr<SubresourceLoader> protect(this); ResourceLoader::didReceiveDataArray(dataArray); // A subresource loader does not load multipart sections progressively. // So don't deliver any data to the loader yet. if (!m_loadingMultipartContent) { CFIndex arrayCount = CFArrayGetCount(dataArray); for (CFIndex i = 0; i < arrayCount; ++i) { if (!m_client) break; CFDataRef data = reinterpret_cast<CFDataRef>(CFArrayGetValueAtIndex(dataArray, i)); didReceiveData(reinterpret_cast<const char *>(CFDataGetBytePtr(data)), static_cast<int>(CFDataGetLength(data)), -1, false); } } }
void InspectorResourceAgent::didReceiveResponse(unsigned long identifier, DocumentLoader* loader, const ResourceResponse& response, ResourceLoader* resourceLoader) { String requestId = IdentifiersFactory::requestId(identifier); RefPtr<TypeBuilder::Network::Response> resourceResponse = buildObjectForResourceResponse(response, loader); InspectorPageAgent::ResourceType type = InspectorPageAgent::OtherResource; long cachedResourceSize = 0; bool isNotModified = response.httpStatusCode() == 304; if (loader) { CachedResource* cachedResource = 0; if (resourceLoader && resourceLoader->isSubresourceLoader() && !isNotModified) cachedResource = static_cast<SubresourceLoader*>(resourceLoader)->cachedResource(); if (!cachedResource) cachedResource = InspectorPageAgent::cachedResource(loader->frame(), response.url()); if (cachedResource) { type = InspectorPageAgent::cachedResourceType(*cachedResource); cachedResourceSize = cachedResource->encodedSize(); // Use mime type from cached resource in case the one in response is empty. if (resourceResponse && response.mimeType().isEmpty()) resourceResponse->setString(TypeBuilder::Network::Response::MimeType, cachedResource->response().mimeType()); m_resourcesData->addCachedResource(requestId, cachedResource); } if (m_loadingXHRSynchronously || m_resourcesData->resourceType(requestId) == InspectorPageAgent::XHRResource) type = InspectorPageAgent::XHRResource; else if (m_resourcesData->resourceType(requestId) == InspectorPageAgent::ScriptResource) type = InspectorPageAgent::ScriptResource; else if (equalIgnoringFragmentIdentifier(response.url(), loader->frameLoader()->icon()->url())) type = InspectorPageAgent::ImageResource; else if (equalIgnoringFragmentIdentifier(response.url(), loader->url()) && !loader->isCommitted()) type = InspectorPageAgent::DocumentResource; m_resourcesData->responseReceived(requestId, m_pageAgent->frameId(loader->frame()), response); } m_resourcesData->setResourceType(requestId, type); m_frontend->responseReceived(requestId, m_pageAgent->frameId(loader->frame()), m_pageAgent->loaderId(loader), currentTime(), InspectorPageAgent::resourceTypeJson(type), resourceResponse); // If we revalidated the resource and got Not modified, send content length following didReceiveResponse // as there will be no calls to didReceiveData from the network stack. if (cachedResourceSize && isNotModified) didReceiveData(identifier, 0, cachedResourceSize, 0); }
void InspectorResourceAgent::didReceiveResponse(unsigned long identifier, DocumentLoader* loader, const ResourceResponse& response, ResourceLoader* resourceLoader) { if (m_hiddenRequestIdentifiers.contains(identifier)) return; String requestId = IdentifiersFactory::requestId(identifier); RefPtr<Inspector::Protocol::Network::Response> resourceResponse = buildObjectForResourceResponse(response, loader); bool isNotModified = response.httpStatusCode() == 304; CachedResource* cachedResource = nullptr; if (resourceLoader && resourceLoader->isSubresourceLoader() && !isNotModified) cachedResource = static_cast<SubresourceLoader*>(resourceLoader)->cachedResource(); if (!cachedResource) cachedResource = InspectorPageAgent::cachedResource(loader->frame(), response.url()); if (cachedResource) { // Use mime type from cached resource in case the one in response is empty. if (resourceResponse && response.mimeType().isEmpty()) resourceResponse->setString(Inspector::Protocol::Network::Response::MimeType, cachedResource->response().mimeType()); m_resourcesData->addCachedResource(requestId, cachedResource); } InspectorPageAgent::ResourceType type = m_resourcesData->resourceType(requestId); InspectorPageAgent::ResourceType newType = cachedResource ? InspectorPageAgent::cachedResourceType(*cachedResource) : type; // FIXME: XHRResource is returned for CachedResource::RawResource, it should be OtherResource unless it truly is an XHR. // RawResource is used for loading worker scripts, and those should stay as ScriptResource and not change to XHRResource. if (type != newType && newType != InspectorPageAgent::XHRResource && newType != InspectorPageAgent::OtherResource) type = newType; m_resourcesData->responseReceived(requestId, m_pageAgent->frameId(loader->frame()), response); m_resourcesData->setResourceType(requestId, type); m_frontendDispatcher->responseReceived(requestId, m_pageAgent->frameId(loader->frame()), m_pageAgent->loaderId(loader), currentTime(), InspectorPageAgent::resourceTypeJson(type), resourceResponse); // If we revalidated the resource and got Not modified, send content length following didReceiveResponse // as there will be no calls to didReceiveData from the network stack. if (isNotModified && cachedResource && cachedResource->encodedSize()) didReceiveData(identifier, nullptr, cachedResource->encodedSize(), 0); }
// private methods void SocketStreamHandle::processMessageOnMainThread(StreamMessage msg) { switch (msg) { case DidOpen: ASSERT(m_state == Open); if (m_client) m_client->didOpenSocketStream(this); break; case DidFail: ASSERT(m_curl_code != CURLE_OK); LOG_CONNECT(Network, "SocketStreamHandleCurl: DidFail, error %d (%s), curl error buffer: %s [%p][thread=%d]\n", m_curl_code, curl_easy_strerror(m_curl_code), m_curl_error_buffer, this, GetCurrentThreadId()); if (m_client) m_client->didFailSocketStream(this, SocketStreamError(m_curl_code, m_url.isEmpty() ? String() : m_url.string())); break; case DidReceiveData: didReceiveData(); break; case DidSelectForWrite: { deref(); // this balances the ref() when spinning up the send wait thread. // LOG(Network, "SocketStreamHandleCurl: DidSelectForWrite [%p][thread=%d]\n", this, GetCurrentThreadId()); if (!m_platformCloseRequested) { if (m_curl_code == CURLE_OK) { sendPendingData(); } else if (m_client) { m_client->didFailSocketStream(this, SocketStreamError(m_curl_code, m_url.isEmpty() ? String() : m_url.string())); } } } break; case DidClose: disconnect(); break; case DidStopRecvLoop: deref(); // this balances the ref() in the constructor. break; } deref(); }
void ResourceLoader::didReceiveData(ResourceHandle*, const char* data, unsigned length, int encodedDataLength) { didReceiveData(data, length, encodedDataLength, DataPayloadBytes); }
void MainResourceLoader::continueAfterContentPolicy(PolicyAction contentPolicy, const ResourceResponse& r) { KURL url = request().url(); const String& mimeType = r.mimeType(); switch (contentPolicy) { case PolicyUse: { // Prevent remote web archives from loading because they can claim to be from any domain and thus avoid cross-domain security checks (4120255). bool isRemoteWebArchive = (equalIgnoringCase("application/x-webarchive", mimeType) #if PLATFORM(GTK) || equalIgnoringCase("message/rfc822", mimeType) #endif || equalIgnoringCase("multipart/related", mimeType)) && !m_substituteData.isValid() && !SchemeRegistry::shouldTreatURLSchemeAsLocal(url.protocol()); if (!frameLoader()->client()->canShowMIMEType(mimeType) || isRemoteWebArchive) { frameLoader()->policyChecker()->cannotShowMIMEType(r); // Check reachedTerminalState since the load may have already been canceled inside of _handleUnimplementablePolicyWithErrorCode::. if (!reachedTerminalState()) stopLoadingForPolicyChange(); return; } break; } case PolicyDownload: { // m_handle can be null, e.g. when loading a substitute resource from application cache. if (!m_handle) { receivedError(cannotShowURLError()); return; } InspectorInstrumentation::continueWithPolicyDownload(m_frame.get(), documentLoader(), identifier(), r); // When starting the request, we didn't know that it would result in download and not navigation. Now we know that main document URL didn't change. // Download may use this knowledge for purposes unrelated to cookies, notably for setting file quarantine data. ResourceRequest request = this->request(); frameLoader()->setOriginalURLForDownloadRequest(request); frameLoader()->client()->download(m_handle.get(), request, r); // It might have gone missing if (frameLoader()) receivedError(interruptedForPolicyChangeError()); return; } case PolicyIgnore: InspectorInstrumentation::continueWithPolicyIgnore(m_frame.get(), documentLoader(), identifier(), r); stopLoadingForPolicyChange(); return; default: ASSERT_NOT_REACHED(); } RefPtr<MainResourceLoader> protect(this); if (r.isHTTP()) { int status = r.httpStatusCode(); if (status < 200 || status >= 300) { bool hostedByObject = frameLoader()->isHostedByObjectElement(); frameLoader()->handleFallbackContent(); // object elements are no longer rendered after we fallback, so don't // keep trying to process data from their load if (hostedByObject) cancel(); } } // we may have cancelled this load as part of switching to fallback content if (!reachedTerminalState()) ResourceLoader::didReceiveResponse(r); if (frameLoader() && !frameLoader()->activeDocumentLoader()->isStopping()) { if (m_substituteData.isValid()) { if (m_substituteData.content()->size()) didReceiveData(m_substituteData.content()->data(), m_substituteData.content()->size(), m_substituteData.content()->size(), true); if (frameLoader() && !frameLoader()->activeDocumentLoader()->isStopping()) didFinishLoading(0); } else if (shouldLoadAsEmptyDocument(url) || frameLoader()->client()->representationExistsForURLScheme(url.protocol())) didFinishLoading(0); } }
void DocumentThreadableLoader::dataReceived(Resource* resource, const char* data, int dataLength) { ASSERT(resource == this->resource()); didReceiveData(resource->identifier(), data, dataLength); }
void ResourceLoader::didReceiveData(ResourceHandle*, const char* data, int length, int encodedDataLength) { InspectorInstrumentationCookie cookie = InspectorInstrumentation::willReceiveResourceData(m_frame.get(), identifier(), encodedDataLength); didReceiveData(data, length, encodedDataLength, false); InspectorInstrumentation::didReceiveResourceData(cookie); }
void DocumentThreadableLoader::loadRequest(const ResourceRequest& request, SecurityCheckPolicy securityCheck) { // Any credential should have been removed from the cross-site requests. const URL& requestURL = request.url(); m_options.setSecurityCheck(securityCheck); ASSERT(m_sameOriginRequest || requestURL.user().isEmpty()); ASSERT(m_sameOriginRequest || requestURL.pass().isEmpty()); if (m_async) { ThreadableLoaderOptions options = m_options; options.setClientCredentialPolicy(DoNotAskClientForCrossOriginCredentials); if (m_actualRequest) { // Don't sniff content or send load callbacks for the preflight request. options.setSendLoadCallbacks(DoNotSendCallbacks); options.setSniffContent(DoNotSniffContent); // Keep buffering the data for the preflight request. options.setDataBufferingPolicy(BufferData); } CachedResourceRequest newRequest(request, options); if (RuntimeEnabledFeatures::sharedFeatures().resourceTimingEnabled()) newRequest.setInitiator(m_options.initiator); ASSERT(!m_resource); m_resource = m_document.cachedResourceLoader().requestRawResource(newRequest); if (m_resource) m_resource->addClient(this); return; } // FIXME: ThreadableLoaderOptions.sniffContent is not supported for synchronous requests. RefPtr<SharedBuffer> data; ResourceError error; ResourceResponse response; unsigned long identifier = std::numeric_limits<unsigned long>::max(); if (m_document.frame()) identifier = m_document.frame()->loader().loadResourceSynchronously(request, m_options.allowCredentials(), m_options.clientCredentialPolicy(), error, response, data); if (!error.isNull() && response.httpStatusCode() <= 0) { if (requestURL.isLocalFile()) { // We don't want XMLHttpRequest to raise an exception for file:// resources, see <rdar://problem/4962298>. // FIXME: XMLHttpRequest quirks should be in XMLHttpRequest code, not in DocumentThreadableLoader.cpp. didReceiveResponse(identifier, response); didFinishLoading(identifier, 0.0); return; } m_client->didFail(error); return; } // FIXME: FrameLoader::loadSynchronously() does not tell us whether a redirect happened or not, so we guess by comparing the // request and response URLs. This isn't a perfect test though, since a server can serve a redirect to the same URL that was // requested. Also comparing the request and response URLs as strings will fail if the requestURL still has its credentials. bool didRedirect = requestURL != response.url(); if (didRedirect && (!isAllowedByContentSecurityPolicy(response.url(), didRedirect) || !isAllowedRedirect(response.url()))) { m_client->didFailRedirectCheck(); return; } didReceiveResponse(identifier, response); if (data) didReceiveData(identifier, data->data(), data->size()); didFinishLoading(identifier, 0.0); }
void DocumentThreadableLoader::dataReceived(CachedResource* resource, const char* data, int dataLength) { ASSERT_UNUSED(resource, resource == m_resource); didReceiveData(m_resource->identifier(), data, dataLength); }
void MainResourceLoader::continueAfterContentPolicy(PolicyAction contentPolicy, const ResourceResponse& r) { KURL url = request().url(); const String& mimeType = r.mimeType(); switch (contentPolicy) { case PolicyUse: { // Prevent remote web archives from loading because they can claim to be from any domain and thus avoid cross-domain security checks (4120255). bool isRemoteWebArchive = (equalIgnoringCase("application/x-webarchive", mimeType) || equalIgnoringCase("multipart/related", mimeType)) && !m_substituteData.isValid() && !url.isLocalFile(); if (!frameLoader()->client()->canShowMIMEType(mimeType) || isRemoteWebArchive) { frameLoader()->policyChecker()->cannotShowMIMEType(r); // Check reachedTerminalState since the load may have already been cancelled inside of _handleUnimplementablePolicyWithErrorCode::. if (!reachedTerminalState()) stopLoadingForPolicyChange(); return; } break; } case PolicyDownload: // m_handle can be null, e.g. when loading a substitute resource from application cache. if (!m_handle) { receivedError(cannotShowURLError()); return; } frameLoader()->client()->download(m_handle.get(), request(), m_handle.get()->firstRequest(), r); // It might have gone missing if (frameLoader()) receivedError(interruptedForPolicyChangeError()); return; case PolicyIgnore: stopLoadingForPolicyChange(); return; default: ASSERT_NOT_REACHED(); } RefPtr<MainResourceLoader> protect(this); if (r.isHTTP()) { int status = r.httpStatusCode(); if (status < 200 || status >= 300) { bool hostedByObject = frameLoader()->isHostedByObjectElement(); frameLoader()->handleFallbackContent(); // object elements are no longer rendered after we fallback, so don't // keep trying to process data from their load if (hostedByObject) cancel(); } } // we may have cancelled this load as part of switching to fallback content if (!reachedTerminalState()) ResourceLoader::didReceiveResponse(r); if (frameLoader() && !frameLoader()->isStopping()) { if (m_substituteData.isValid()) { if (m_substituteData.content()->size()) didReceiveData(m_substituteData.content()->data(), m_substituteData.content()->size(), m_substituteData.content()->size(), true); if (frameLoader() && !frameLoader()->isStopping()) didFinishLoading(0); } else if (shouldLoadAsEmptyDocument(url) || frameLoader()->client()->representationExistsForURLScheme(url.protocol())) didFinishLoading(0); } }
void DocumentThreadableLoader::dataReceived(Resource* resource, const char* data, int dataLength) { ASSERT_UNUSED(resource, resource == this->resource()); didReceiveData(data, dataLength); }
void DocumentThreadableLoader::loadRequest(const ResourceRequest& request) { // Any credential should have been removed from the cross-site requests. const KURL& requestURL = request.url(); ASSERT(m_sameOriginRequest || requestURL.user().isEmpty()); ASSERT(m_sameOriginRequest || requestURL.pass().isEmpty()); ThreadableLoaderOptions options = m_options; if (m_async) { if (m_actualRequest) { options.sniffContent = DoNotSniffContent; options.dataBufferingPolicy = BufferData; } if (m_options.timeoutMilliseconds > 0) m_timeoutTimer.startOneShot(m_options.timeoutMilliseconds / 1000.0); FetchRequest newRequest(request, m_options.initiator, options); ASSERT(!resource()); setResource(m_document->fetcher()->fetchRawResource(newRequest)); if (resource() && resource()->loader()) { unsigned long identifier = resource()->identifier(); InspectorInstrumentation::documentThreadableLoaderStartedLoadingForClient(m_document, identifier, m_client); } return; } FetchRequest fetchRequest(request, m_options.initiator, options); ResourcePtr<Resource> resource = m_document->fetcher()->fetchSynchronously(fetchRequest); ResourceResponse response = resource ? resource->response() : ResourceResponse(); unsigned long identifier = resource ? resource->identifier() : std::numeric_limits<unsigned long>::max(); ResourceError error = resource ? resource->resourceError() : ResourceError(); InspectorInstrumentation::documentThreadableLoaderStartedLoadingForClient(m_document, identifier, m_client); if (!resource) { m_client->didFail(error); return; } // No exception for file:/// resources, see <rdar://problem/4962298>. // Also, if we have an HTTP response, then it wasn't a network error in fact. if (!error.isNull() && !requestURL.isLocalFile() && response.httpStatusCode() <= 0) { m_client->didFail(error); return; } // FIXME: A synchronous request does not tell us whether a redirect happened or not, so we guess by comparing the // request and response URLs. This isn't a perfect test though, since a server can serve a redirect to the same URL that was // requested. Also comparing the request and response URLs as strings will fail if the requestURL still has its credentials. if (requestURL != response.url() && (!isAllowedByPolicy(response.url()) || !isAllowedRedirect(response.url()))) { m_client->didFailRedirectCheck(); return; } didReceiveResponse(identifier, response); SharedBuffer* data = resource->resourceBuffer(); if (data) didReceiveData(data->data(), data->size()); didFinishLoading(identifier, 0.0); }
void ResourceHandleClient::didReceiveBuffer(ResourceHandle* handle, PassRefPtr<SharedBuffer> buffer, int encodedDataLength) { didReceiveData(handle, buffer->data(), buffer->size(), encodedDataLength); }
void ResourceLoader::didReceiveData(ResourceHandle*, const char* data, int length, int lengthReceived) { didReceiveData(data, length, lengthReceived, false); }
void DocumentThreadableLoader::loadRequest(const ResourceRequest& request, SecurityCheckPolicy securityCheck) { // Any credential should have been removed from the cross-site requests. const KURL& requestURL = request.url(); m_options.securityCheck = securityCheck; ASSERT(m_sameOriginRequest || requestURL.user().isEmpty()); ASSERT(m_sameOriginRequest || requestURL.pass().isEmpty()); if (m_async) { ThreadableLoaderOptions options = m_options; options.clientCredentialPolicy = DoNotAskClientForCrossOriginCredentials; if (m_actualRequest) { // Don't sniff content or send load callbacks for the preflight request. options.sendLoadCallbacks = DoNotSendCallbacks; options.sniffContent = DoNotSniffContent; // Keep buffering the data for the preflight request. options.dataBufferingPolicy = BufferData; } CachedResourceRequest newRequest(request, options); #if ENABLE(RESOURCE_TIMING) newRequest.setInitiator(m_options.initiator); #endif ASSERT(!m_resource); m_resource = m_document->cachedResourceLoader()->requestRawResource(newRequest); if (m_resource) { #if ENABLE(INSPECTOR) if (m_resource->loader()) { unsigned long identifier = m_resource->loader()->identifier(); InspectorInstrumentation::documentThreadableLoaderStartedLoadingForClient(m_document, identifier, m_client); } #endif m_resource->addClient(this); } return; } // FIXME: ThreadableLoaderOptions.sniffContent is not supported for synchronous requests. Vector<char> data; ResourceError error; ResourceResponse response; unsigned long identifier = std::numeric_limits<unsigned long>::max(); if (m_document->frame()) identifier = m_document->frame()->loader()->loadResourceSynchronously(request, m_options.allowCredentials, m_options.clientCredentialPolicy, error, response, data); InspectorInstrumentation::documentThreadableLoaderStartedLoadingForClient(m_document, identifier, m_client); // No exception for file:/// resources, see <rdar://problem/4962298>. // Also, if we have an HTTP response, then it wasn't a network error in fact. if (!error.isNull() && !requestURL.isLocalFile() && response.httpStatusCode() <= 0) { m_client->didFail(error); return; } // FIXME: FrameLoader::loadSynchronously() does not tell us whether a redirect happened or not, so we guess by comparing the // request and response URLs. This isn't a perfect test though, since a server can serve a redirect to the same URL that was // requested. Also comparing the request and response URLs as strings will fail if the requestURL still has its credentials. if (requestURL != response.url() && !isAllowedRedirect(response.url())) { m_client->didFailRedirectCheck(); return; } didReceiveResponse(identifier, response); const char* bytes = static_cast<const char*>(data.data()); int len = static_cast<int>(data.size()); didReceiveData(identifier, bytes, len); didFinishLoading(identifier, 0.0); }
bool MultipartHandle::processContent() { /* The allowed transitions between the states: Check Boundary | /-- In Boundary <----\ | | | | In Header | | | | | In Content | | | | | End Boundary ----/ | | \-----> End */ switch (m_state) { case CheckBoundary: { if (m_buffer.size() < m_boundaryLength) { // We don't have enough data, so just skip. return false; } // Check for the boundary string. size_t boundaryStart; size_t lastPartialMatch; if (!checkForBoundary(boundaryStart, lastPartialMatch) && boundaryStart == notFound) { // Did not find the boundary start in this chunk. // Skip ahead to the last valid looking boundary character and start again. m_buffer.remove(0, lastPartialMatch); return false; } // Found the boundary start. // Consume everything before that and also the boundary m_buffer.remove(0, boundaryStart + m_boundaryLength); m_state = InBoundary; } // Fallthrough. case InBoundary: { // Now the first two characters should be: \r\n if (m_buffer.size() < 2) return false; const char* content = m_buffer.data(); // By default we'll remove 2 characters at the end. // The \r and \n as stated in the multipart RFC. size_t removeCount = 2; if (content[0] != '\r' || content[1] != '\n') { // There should be a \r and a \n but it seems that's not the case. // So we'll check for a simple \n. Not really RFC compatible but servers do tricky things. if (content[0] != '\n') { // Also no \n so just go to the end. m_state = End; return false; } // Found a simple \n so remove just that. removeCount = 1; } // Consume the characters. m_buffer.remove(0, removeCount); m_headers.clear(); m_state = InHeader; } // Fallthrough. case InHeader: { // Process the headers. if (!parseHeadersIfPossible()) { // Parsing of headers failed, try again later. return false; } didReceiveResponse(); m_state = InContent; } // Fallthrough. case InContent: { if (m_buffer.isEmpty()) return false; size_t boundaryStart = notFound; size_t lastPartialMatch; if (!checkForBoundary(boundaryStart, lastPartialMatch) && boundaryStart == notFound) { // Did not find the boundary start, all data up to the lastPartialMatch is ok. didReceiveData(lastPartialMatch); m_buffer.remove(0, lastPartialMatch); return false; } // There was a boundary start (or end we'll check that later), push out part of the data. didReceiveData(boundaryStart); m_buffer.remove(0, boundaryStart + m_boundaryLength); m_state = EndBoundary; } // Fallthrough. case EndBoundary: { if (m_buffer.size() < 2) return false; // Not enough data to check. Return later when there is more data. // We'll decide if this is a closing boundary or an opening one. const char* content = m_buffer.data(); if (content[0] == '-' && content[1] == '-') { // This is a closing boundary. Close down the handler. m_state = End; return false; } // This was a simple content separator not a closing one. // Go to before the content processing. m_state = InBoundary; break; } case End: // We are done. Nothing to do anymore. return false; default: ASSERT_NOT_REACHED(); return false; } return true; // There are still things to process, so go for it. }