FetchResponseData* FetchResponseData::createCORSFilteredResponse( const HTTPHeaderSet& exposedHeaders) const { DCHECK_EQ(m_type, DefaultType); // "A CORS filtered response is a filtered response whose type is |CORS|, // header list excludes all headers in internal response's header list, // except those whose name is either one of `Cache-Control`, // `Content-Language`, `Content-Type`, `Expires`, `Last-Modified`, and // `Pragma`, and except those whose name is one of the values resulting from // parsing `Access-Control-Expose-Headers` in internal response's header // list." FetchResponseData* response = new FetchResponseData(CORSType, m_status, m_statusMessage); response->setURLList(m_urlList); for (size_t i = 0; i < m_headerList->size(); ++i) { const FetchHeaderList::Header* header = m_headerList->list()[i].get(); const String& name = header->first; const bool explicitlyExposed = exposedHeaders.contains(name); if (isOnAccessControlResponseHeaderWhitelist(name) || (explicitlyExposed && !FetchUtils::isForbiddenResponseHeaderName(name))) { if (explicitlyExposed) response->m_corsExposedHeaderNames.add(name); response->m_headerList->append(name, header->second); } } response->m_buffer = m_buffer; response->m_mimeType = m_mimeType; response->m_internalResponse = const_cast<FetchResponseData*>(this); return response; }
FetchResponseData* FetchResponseData::createCORSFilteredResponse() { // "A CORS filtered response is a filtered response whose type is |CORS|, // header list excludes all headers in internal response's header list, // except those whose name is either one of `Cache-Control`, // `Content-Language`, `Content-Type`, `Expires`, `Last-Modified`, and // `Pragma`, and except those whose name is one of the values resulting from // parsing `Access-Control-Expose-Headers` in internal response's header // list." FetchResponseData* response = new FetchResponseData(CORSType, m_status, m_statusMessage); response->m_url = m_url; HTTPHeaderSet accessControlExposeHeaderSet; String accessControlExposeHeaders; if (m_headerList->get("access-control-expose-headers", accessControlExposeHeaders)) parseAccessControlExposeHeadersAllowList(accessControlExposeHeaders, accessControlExposeHeaderSet); for (size_t i = 0; i < m_headerList->size(); ++i) { const FetchHeaderList::Header* header = m_headerList->list()[i].get(); if (!isOnAccessControlResponseHeaderWhitelist(header->first) && !accessControlExposeHeaderSet.contains(header->first)) continue; response->m_headerList->append(header->first, header->second); } response->m_buffer = m_buffer; response->m_mimeType = m_mimeType; response->m_internalResponse = this; return response; }
void WebAssociatedURLLoaderImpl::ClientAdapter::didReceiveResponse( unsigned long, const ResourceResponse& response, std::unique_ptr<WebDataConsumerHandle> handle) { ALLOW_UNUSED_LOCAL(handle); DCHECK(!handle); if (!m_client) return; if (m_options.exposeAllResponseHeaders || m_options.crossOriginRequestPolicy != WebAssociatedURLLoaderOptions:: CrossOriginRequestPolicyUseAccessControl) { // Use the original ResourceResponse. m_client->didReceiveResponse(WrappedResourceResponse(response)); return; } HTTPHeaderSet exposedHeaders; extractCorsExposedHeaderNamesList(response, exposedHeaders); HTTPHeaderSet blockedHeaders; for (const auto& header : response.httpHeaderFields()) { if (FetchUtils::isForbiddenResponseHeaderName(header.key) || (!isOnAccessControlResponseHeaderWhitelist(header.key) && !exposedHeaders.contains(header.key))) blockedHeaders.add(header.key); } if (blockedHeaders.isEmpty()) { // Use the original ResourceResponse. m_client->didReceiveResponse(WrappedResourceResponse(response)); return; } // If there are blocked headers, copy the response so we can remove them. WebURLResponse validatedResponse = WrappedResourceResponse(response); for (const auto& header : blockedHeaders) validatedResponse.clearHTTPHeaderField(header); m_client->didReceiveResponse(validatedResponse); }