Beispiel #1
0
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;
}
Beispiel #2
0
void parseAccessControlExposeHeadersAllowList(const String& headerValue, HTTPHeaderSet& headerSet)
{
    Vector<String> headers;
    headerValue.split(',', false, headers);
    for (unsigned headerCount = 0; headerCount < headers.size(); headerCount++) {
        String strippedHeader = headers[headerCount].stripWhiteSpace();
        if (!strippedHeader.isEmpty())
            headerSet.add(strippedHeader);
    }
}
Beispiel #3
0
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);
}
Beispiel #4
0
void ForeignFetchRespondWithObserver::responseWasFulfilled(
    const ScriptValue& value) {
  ASSERT(getExecutionContext());
  ExceptionState exceptionState(value.isolate(), ExceptionState::UnknownContext,
                                "ForeignFetchEvent", "respondWith");
  ForeignFetchResponse foreignFetchResponse =
      ScriptValue::to<ForeignFetchResponse>(toIsolate(getExecutionContext()),
                                            value, exceptionState);
  if (exceptionState.hadException()) {
    exceptionState.clearException();
    responseWasRejected(WebServiceWorkerResponseErrorNoForeignFetchResponse);
    return;
  }

  Response* response = foreignFetchResponse.response();
  const FetchResponseData* internalResponse = response->response();
  const bool isOpaque =
      internalResponse->getType() == FetchResponseData::OpaqueType ||
      internalResponse->getType() == FetchResponseData::OpaqueRedirectType;
  if (internalResponse->getType() != FetchResponseData::DefaultType)
    internalResponse = internalResponse->internalResponse();

  if (!foreignFetchResponse.hasOrigin()) {
    if (foreignFetchResponse.hasHeaders() &&
        !foreignFetchResponse.headers().isEmpty()) {
      responseWasRejected(
          WebServiceWorkerResponseErrorForeignFetchHeadersWithoutOrigin);
      return;
    }

    // If response isn't already opaque, make it opaque.
    if (!isOpaque) {
      FetchResponseData* opaqueData =
          internalResponse->createOpaqueFilteredResponse();
      response = Response::create(getExecutionContext(), opaqueData);
    }
  } else if (m_requestOrigin->toString() != foreignFetchResponse.origin()) {
    responseWasRejected(
        WebServiceWorkerResponseErrorForeignFetchMismatchedOrigin);
    return;
  } else if (!isOpaque) {
    HTTPHeaderSet headers;
    if (foreignFetchResponse.hasHeaders()) {
      for (const String& header : foreignFetchResponse.headers())
        headers.add(header);
      if (response->response()->getType() == FetchResponseData::CORSType) {
        const HTTPHeaderSet& existingHeaders =
            response->response()->corsExposedHeaderNames();
        HTTPHeaderSet headersToRemove;
        for (HTTPHeaderSet::iterator it = headers.begin(); it != headers.end();
             ++it) {
          if (!existingHeaders.contains(*it))
            headersToRemove.add(*it);
        }
        headers.removeAll(headersToRemove);
      }
    }
    FetchResponseData* responseData =
        internalResponse->createCORSFilteredResponse(headers);
    response = Response::create(getExecutionContext(), responseData);
  }

  RespondWithObserver::responseWasFulfilled(
      ScriptValue::from(value.getScriptState(), response));
}