TEST(ImageResourceTest, MultipartImage) { ResourceFetcher* fetcher = ResourceFetcher::create(nullptr); KURL testURL(ParsedURLString, "http://www.test.com/cancelTest.html"); URLTestHelpers::registerMockedURLLoad(testURL, "cancelTest.html", "text/html"); // Emulate starting a real load, but don't expect any "real" WebURLLoaderClient callbacks. ResourcePtr<ImageResource> cachedImage = new ImageResource(ResourceRequest(testURL), nullptr); cachedImage->setIdentifier(createUniqueIdentifier()); cachedImage->load(fetcher, ResourceLoaderOptions()); Platform::current()->unitTestSupport()->unregisterMockedURL(testURL); MockImageResourceClient client(cachedImage); EXPECT_EQ(Resource::Pending, cachedImage->status()); // Send the multipart response. No image or data buffer is created. // Note that the response must be routed through ResourceLoader to // ensure the load is flagged as multipart. ResourceResponse multipartResponse(KURL(), "multipart/x-mixed-replace", 0, nullAtom, String()); cachedImage->loader()->didReceiveResponse(nullptr, WrappedResourceResponse(multipartResponse), nullptr); ASSERT_FALSE(cachedImage->resourceBuffer()); ASSERT_FALSE(cachedImage->hasImage()); ASSERT_EQ(client.imageChangedCount(), 0); ASSERT_FALSE(client.notifyFinishedCalled()); // Send the response for the first real part. No image or data buffer is created. const char* svgData = "<svg xmlns='http://www.w3.org/2000/svg' width='1' height='1'><rect width='1' height='1' fill='green'/></svg>"; unsigned svgDataLength = strlen(svgData); ResourceResponse payloadResponse(KURL(), "image/svg+xml", svgDataLength, nullAtom, String()); cachedImage->loader()->didReceiveResponse(nullptr, WrappedResourceResponse(payloadResponse), nullptr); ASSERT_FALSE(cachedImage->resourceBuffer()); ASSERT_FALSE(cachedImage->hasImage()); ASSERT_EQ(client.imageChangedCount(), 0); ASSERT_FALSE(client.notifyFinishedCalled()); // The first bytes arrive. The data buffer is created, but no image is created. cachedImage->appendData(svgData, svgDataLength); ASSERT_TRUE(cachedImage->resourceBuffer()); ASSERT_EQ(cachedImage->resourceBuffer()->size(), svgDataLength); ASSERT_FALSE(cachedImage->hasImage()); ASSERT_EQ(client.imageChangedCount(), 0); ASSERT_FALSE(client.notifyFinishedCalled()); // This part finishes. The image is created, callbacks are sent, and the data buffer is cleared. cachedImage->finish(); ASSERT_FALSE(cachedImage->resourceBuffer()); ASSERT_FALSE(cachedImage->errorOccurred()); ASSERT_TRUE(cachedImage->hasImage()); ASSERT_FALSE(cachedImage->image()->isNull()); ASSERT_EQ(cachedImage->image()->width(), 1); ASSERT_EQ(cachedImage->image()->height(), 1); ASSERT_EQ(client.imageChangedCount(), 2); ASSERT_TRUE(client.notifyFinishedCalled()); }
TEST(RawResourceTest, RevalidationSucceededForResourceWithoutBody) { ResourcePtr<Resource> resource = new RawResource(ResourceRequest("data:text/html,"), Resource::Raw); ResourceResponse response; response.setHTTPStatusCode(200); resource->responseReceived(response, nullptr); resource->finish(); memoryCache()->add(resource.get()); // Simulate a successful revalidation. resource->setRevalidatingRequest(ResourceRequest("data:text/html,")); OwnPtr<DummyClient> client = adoptPtr(new DummyClient); resource->addClient(client.get()); ResourceResponse revalidatingResponse; revalidatingResponse.setHTTPStatusCode(304); resource->responseReceived(revalidatingResponse, nullptr); EXPECT_FALSE(resource->isCacheValidator()); EXPECT_EQ(200, resource->response().httpStatusCode()); EXPECT_EQ(nullptr, resource->resourceBuffer()); EXPECT_EQ(memoryCache()->resourceForURL(KURL(ParsedURLString, "data:text/html,")), resource.get()); memoryCache()->remove(resource.get()); resource->removeClient(client.get()); EXPECT_FALSE(resource->hasClients()); EXPECT_FALSE(client->called()); EXPECT_EQ(0u, client->data().size()); }
static xmlDocPtr docLoaderFunc(const xmlChar* uri, xmlDictPtr, int options, void* ctxt, xsltLoadType type) { if (!globalProcessor) return 0; switch (type) { case XSLT_LOAD_DOCUMENT: { xsltTransformContextPtr context = (xsltTransformContextPtr)ctxt; xmlChar* base = xmlNodeGetBase(context->document->doc, context->node); KURL url(KURL(ParsedURLString, reinterpret_cast<const char*>(base)), reinterpret_cast<const char*>(uri)); xmlFree(base); ResourceLoaderOptions fetchOptions(ResourceFetcher::defaultResourceOptions()); FetchRequest request(ResourceRequest(url), FetchInitiatorTypeNames::xml, fetchOptions); request.setOriginRestriction(FetchRequest::RestrictToSameOrigin); ResourcePtr<Resource> resource = globalResourceFetcher->fetchSynchronously(request); if (!resource || !globalProcessor) return 0; PageConsole* console = 0; Frame* frame = globalProcessor->xslStylesheet()->ownerDocument()->frame(); if (frame && frame->page()) console = &frame->page()->console(); xmlSetStructuredErrorFunc(console, XSLTProcessor::parseErrorFunc); xmlSetGenericErrorFunc(console, XSLTProcessor::genericErrorFunc); // We don't specify an encoding here. Neither Gecko nor WinIE respects // the encoding specified in the HTTP headers. SharedBuffer* data = resource->resourceBuffer(); xmlDocPtr doc = data ? xmlReadMemory(data->data(), data->size(), (const char*)uri, 0, options) : 0; xmlSetStructuredErrorFunc(0, 0); xmlSetGenericErrorFunc(0, 0); return doc; } case XSLT_LOAD_STYLESHEET: return globalProcessor->xslStylesheet()->locateStylesheetSubResource(((xsltStylesheetPtr)ctxt)->doc, uri); default: break; } return 0; }
void DocumentThreadableLoader::loadRequest(const ResourceRequest& request, ResourceLoaderOptions resourceLoaderOptions) { // 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()); // Update resourceLoaderOptions with enforced values. if (m_forceDoNotAllowStoredCredentials) resourceLoaderOptions.allowCredentials = DoNotAllowStoredCredentials; resourceLoaderOptions.securityOrigin = m_securityOrigin; if (m_async) { if (!m_actualRequest.isNull()) resourceLoaderOptions.dataBufferingPolicy = BufferData; if (m_options.timeoutMilliseconds > 0) m_timeoutTimer.startOneShot(m_options.timeoutMilliseconds / 1000.0, BLINK_FROM_HERE); FetchRequest newRequest(request, m_options.initiator, resourceLoaderOptions); if (m_options.crossOriginRequestPolicy == AllowCrossOriginRequests) newRequest.setOriginRestriction(FetchRequest::NoOriginRestriction); ASSERT(!resource()); if (request.requestContext() == WebURLRequest::RequestContextVideo || request.requestContext() == WebURLRequest::RequestContextAudio) setResource(RawResource::fetchMedia(newRequest, document().fetcher())); else if (request.requestContext() == WebURLRequest::RequestContextManifest) setResource(RawResource::fetchManifest(newRequest, document().fetcher())); else setResource(RawResource::fetch(newRequest, document().fetcher())); if (resource() && resource()->loader()) { unsigned long identifier = resource()->identifier(); InspectorInstrumentation::documentThreadableLoaderStartedLoadingForClient(m_document, identifier, m_client); } return; } FetchRequest fetchRequest(request, m_options.initiator, resourceLoaderOptions); if (m_options.crossOriginRequestPolicy == AllowCrossOriginRequests) fetchRequest.setOriginRestriction(FetchRequest::NoOriginRestriction); ResourcePtr<Resource> resource = RawResource::fetchSynchronously(fetchRequest, document().fetcher()); 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() && (!isAllowedByContentSecurityPolicy(response.url(), ContentSecurityPolicy::DidRedirect) || !isAllowedRedirect(response.url()))) { m_client->didFailRedirectCheck(); return; } handleResponse(identifier, response, nullptr); // handleResponse() may detect an error. In such a case (check |m_client| // as it gets reset by clear() call), skip the rest. // // |this| is alive here since loadResourceSynchronously() keeps it alive // until the end of the function. if (!m_client) return; SharedBuffer* data = resource->resourceBuffer(); if (data) handleReceivedData(data->data(), data->size()); // The client may cancel this loader in handleReceivedData(). In such a // case, skip the rest. if (!m_client) return; handleSuccessfulFinish(identifier, 0.0); }
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); }