Changeset 222728 in webkit


Ignore:
Timestamp:
Oct 2, 2017 12:00:17 PM (7 years ago)
Author:
commit-queue@webkit.org
Message:

[CURL] Should handle redirects in WebCore
https://bugs.webkit.org/show_bug.cgi?id=21242

Patch by Basuke Suzuki <Basuke Suzuki> on 2017-10-02
Reviewed by Alex Christensen.

  • platform/network/ResourceHandle.cpp:
  • platform/network/curl/CurlContext.cpp:

(WebCore::CurlHandle::enableAutoReferer): Deleted.

  • platform/network/curl/CurlContext.h:
  • platform/network/curl/CurlRequest.cpp:

(WebCore::CurlRequest::setupTransfer):
(WebCore::CurlRequest::didReceiveHeader):
(WebCore::CurlRequest::didReceiveData):

  • platform/network/curl/ResourceHandleCurl.cpp:

(WebCore::ResourceHandle::start):
(WebCore::ResourceHandle::continueDidReceiveResponse):
(WebCore::ResourceHandle::continueWillSendRequest):

  • platform/network/curl/ResourceHandleCurlDelegate.cpp:

(WebCore::ResourceHandleCurlDelegate::curlDidReceiveResponse):
(WebCore::ResourceHandleCurlDelegate::shouldRedirectAsGET):
(WebCore::ResourceHandleCurlDelegate::willSendRequest):
(WebCore::ResourceHandleCurlDelegate::continueWillSendRequest):
(WebCore::ResourceHandleCurlDelegate::continueAfterWillSendRequest):

  • platform/network/curl/ResourceHandleCurlDelegate.h:
  • platform/network/curl/ResourceResponse.h:
  • platform/network/curl/ResourceResponseCurl.cpp:

(WebCore::ResourceResponse::shouldRedirect):
(WebCore::ResourceResponse::isMovedPermanently const):
(WebCore::ResourceResponse::isFound const):
(WebCore::ResourceResponse::isSeeOther const):
(WebCore::ResourceResponse::isRedirection const): Deleted.

Location:
trunk/Source/WebCore
Files:
10 edited

Legend:

Unmodified
Added
Removed
  • trunk/Source/WebCore/ChangeLog

    r222726 r222728  
     12017-10-02  Basuke Suzuki  <Basuke.Suzuki@sony.com>
     2
     3        [CURL] Should handle redirects in WebCore
     4        https://bugs.webkit.org/show_bug.cgi?id=21242
     5
     6        Reviewed by Alex Christensen.
     7
     8        * platform/network/ResourceHandle.cpp:
     9        * platform/network/curl/CurlContext.cpp:
     10        (WebCore::CurlHandle::enableAutoReferer): Deleted.
     11        * platform/network/curl/CurlContext.h:
     12        * platform/network/curl/CurlRequest.cpp:
     13        (WebCore::CurlRequest::setupTransfer):
     14        (WebCore::CurlRequest::didReceiveHeader):
     15        (WebCore::CurlRequest::didReceiveData):
     16        * platform/network/curl/ResourceHandleCurl.cpp:
     17        (WebCore::ResourceHandle::start):
     18        (WebCore::ResourceHandle::continueDidReceiveResponse):
     19        (WebCore::ResourceHandle::continueWillSendRequest):
     20        * platform/network/curl/ResourceHandleCurlDelegate.cpp:
     21        (WebCore::ResourceHandleCurlDelegate::curlDidReceiveResponse):
     22        (WebCore::ResourceHandleCurlDelegate::shouldRedirectAsGET):
     23        (WebCore::ResourceHandleCurlDelegate::willSendRequest):
     24        (WebCore::ResourceHandleCurlDelegate::continueWillSendRequest):
     25        (WebCore::ResourceHandleCurlDelegate::continueAfterWillSendRequest):
     26        * platform/network/curl/ResourceHandleCurlDelegate.h:
     27        * platform/network/curl/ResourceResponse.h:
     28        * platform/network/curl/ResourceResponseCurl.cpp:
     29        (WebCore::ResourceResponse::shouldRedirect):
     30        (WebCore::ResourceResponse::isMovedPermanently const):
     31        (WebCore::ResourceResponse::isFound const):
     32        (WebCore::ResourceResponse::isSeeOther const):
     33        (WebCore::ResourceResponse::isRedirection const): Deleted.
     34
    1352017-10-02  Antti Koivisto  <antti@apple.com>
    236
  • trunk/Source/WebCore/platform/network/ResourceHandle.cpp

    r222467 r222728  
    171171}
    172172
    173 #if !PLATFORM(COCOA) && !USE(CFURLCONNECTION) && !USE(SOUP)
     173#if !PLATFORM(COCOA) && !USE(CFURLCONNECTION) && !USE(SOUP) && !USE(CURL)
    174174// ResourceHandle never uses async client calls on these platforms yet.
    175175void ResourceHandle::continueWillSendRequest(ResourceRequest&&)
  • trunk/Source/WebCore/platform/network/curl/CurlContext.cpp

    r222521 r222728  
    426426}
    427427
    428 void CurlHandle::enableAutoReferer()
    429 {
    430     curl_easy_setopt(m_handle, CURLOPT_AUTOREFERER, 1L);
    431 }
    432 
    433428void CurlHandle::enableHttpAuthentication(long option)
    434429{
  • trunk/Source/WebCore/platform/network/curl/CurlContext.h

    r222521 r222728  
    249249
    250250    void enableFollowLocation();
    251     void enableAutoReferer();
    252251
    253252    void enableHttpAuthentication(long);
  • trunk/Source/WebCore/platform/network/curl/CurlRequest.cpp

    r222665 r222728  
    170170    m_curlHandle->enableTimeout();
    171171
    172     m_curlHandle->enableAutoReferer();
    173     m_curlHandle->enableFollowLocation();
    174172    m_curlHandle->enableProxyIfExists();
    175173    m_curlHandle->enableCookieJarIfExists();
     
    276274    }
    277275
    278     // If the FOLLOWLOCATION option is enabled for the curl handle then
    279     // curl will follow the redirections internally. Thus this header callback
    280     // will be called more than one time with the line starting "HTTP" for one job.
    281 
    282     m_response.url = m_curlHandle->getEffectiveURL();
     276    m_response.url = m_request.url();
    283277    m_response.statusCode = statusCode;
    284278
     
    308302
    309303    auto receiveBytes = buffer->size();
    310 
    311     // this shouldn't be necessary but apparently is. CURL writes the data
    312     // of html page even if it is a redirect that was handled internally
    313     // can be observed e.g. on gmail.com
    314     auto statusCode = m_curlHandle->getResponseCode();
    315     if (statusCode && (300 <= *statusCode) && (*statusCode < 400))
    316         return receiveBytes;
    317304
    318305    if (receiveBytes) {
  • trunk/Source/WebCore/platform/network/curl/ResourceHandleCurl.cpp

    r222665 r222728  
    6666        return false;
    6767
     68    // Only allow the POST and GET methods for non-HTTP requests.
     69    const ResourceRequest& request = firstRequest();
     70    if (!request.url().protocolIsInHTTPFamily() && request.httpMethod() != "GET" && request.httpMethod() != "POST") {
     71        scheduleFailure(InvalidURLFailure); // Error must not be reported immediately
     72        return true;
     73    }
     74
    6875    d->m_delegate = adoptRef(new ResourceHandleCurlDelegate(this));
    6976    return d->m_delegate->start();
     
    251258}
    252259
     260void ResourceHandle::continueDidReceiveResponse()
     261{
     262    notImplemented();
     263}
     264
     265void ResourceHandle::continueWillSendRequest(ResourceRequest&& request)
     266{
     267    ASSERT(isMainThread());
     268    ASSERT(!client() || client()->usesAsyncCallbacks());
     269
     270    if (d->m_delegate)
     271        d->m_delegate->continueWillSendRequest(WTFMove(request));
     272}
     273
    253274} // namespace WebCore
    254275
  • trunk/Source/WebCore/platform/network/curl/ResourceHandleCurlDelegate.cpp

    r222665 r222728  
    202202    }
    203203
    204     // HTTP redirection
    205     if (response().isRedirection()) {
    206         String location = response().httpHeaderField(HTTPHeaderName::Location);
    207         if (!location.isEmpty()) {
    208             URL newURL = URL(m_firstRequest.url(), location);
    209 
    210             ResourceRequest redirectedRequest = m_firstRequest;
    211             redirectedRequest.setURL(newURL);
    212             ResourceResponse localResponse = response();
    213             if (m_handle->client())
    214                 m_handle->client()->willSendRequest(m_handle, WTFMove(redirectedRequest), WTFMove(localResponse));
    215 
    216             m_firstRequest.setURL(newURL);
    217 
    218             return;
    219         }
     204    if (response().shouldRedirect()) {
     205        willSendRequest();
     206        return;
    220207    }
    221208
     
    288275    CurlCacheManager::getInstance().didFail(*m_handle);
    289276    m_handle->client()->didFail(m_handle, resourceError);
     277}
     278
     279bool ResourceHandleCurlDelegate::shouldRedirectAsGET(const ResourceRequest& request, bool crossOrigin)
     280{
     281    if ((request.httpMethod() == "GET") || (request.httpMethod() == "HEAD"))
     282        return false;
     283
     284    if (!request.url().protocolIsInHTTPFamily())
     285        return true;
     286
     287    if (response().isSeeOther())
     288        return true;
     289
     290    if ((response().isMovedPermanently() || response().isFound()) && (request.httpMethod() == "POST"))
     291        return true;
     292
     293    if (crossOrigin && (request.httpMethod() == "DELETE"))
     294        return true;
     295
     296    return false;
     297}
     298
     299void ResourceHandleCurlDelegate::willSendRequest()
     300{
     301    ASSERT(isMainThread());
     302
     303    static const int maxRedirects = 20;
     304
     305    if (m_redirectCount++ > maxRedirects) {
     306        m_handle->client()->didFail(m_handle, ResourceError::httpError(CURLE_TOO_MANY_REDIRECTS, response().url()));
     307        return;
     308    }
     309
     310    String location = response().httpHeaderField(HTTPHeaderName::Location);
     311    URL newURL = URL(m_firstRequest.url(), location);
     312    bool crossOrigin = !protocolHostAndPortAreEqual(m_firstRequest.url(), newURL);
     313
     314    ResourceRequest newRequest = m_firstRequest;
     315    newRequest.setURL(newURL);
     316
     317    if (shouldRedirectAsGET(newRequest, crossOrigin)) {
     318        newRequest.setHTTPMethod("GET");
     319        newRequest.setHTTPBody(nullptr);
     320        newRequest.clearHTTPContentType();
     321    }
     322
     323    // Should not set Referer after a redirect from a secure resource to non-secure one.
     324    if (!newURL.protocolIs("https") && protocolIs(newRequest.httpReferrer(), "https") && m_handle->context()->shouldClearReferrerOnHTTPSToHTTPRedirect())
     325        newRequest.clearHTTPReferrer();
     326
     327    m_user = newURL.user();
     328    m_pass = newURL.pass();
     329    newRequest.removeCredentials();
     330
     331    if (crossOrigin) {
     332        // If the network layer carries over authentication headers from the original request
     333        // in a cross-origin redirect, we want to clear those headers here.
     334        newRequest.clearHTTPAuthorization();
     335        newRequest.clearHTTPOrigin();
     336    }
     337
     338    ResourceResponse responseCopy = response();
     339    if (m_handle->client()->usesAsyncCallbacks())
     340        m_handle->client()->willSendRequestAsync(m_handle, WTFMove(newRequest), WTFMove(responseCopy));
     341    else {
     342        auto request = m_handle->client()->willSendRequest(m_handle, WTFMove(newRequest), WTFMove(responseCopy));
     343        continueAfterWillSendRequest(WTFMove(request));
     344    }
     345}
     346
     347void ResourceHandleCurlDelegate::continueWillSendRequest(ResourceRequest&& request)
     348{
     349    ASSERT(isMainThread());
     350
     351    continueAfterWillSendRequest(WTFMove(request));
     352}
     353
     354void ResourceHandleCurlDelegate::continueAfterWillSendRequest(ResourceRequest&& request)
     355{
     356    ASSERT(isMainThread());
     357
     358    // willSendRequest might cancel the load.
     359    if (cancelledOrClientless() || !m_curlRequest)
     360        return;
     361
     362    m_currentRequest = WTFMove(request);
     363
     364    bool isSyncRequest = m_curlRequest->isSyncRequest();
     365    m_curlRequest->cancel();
     366    m_curlRequest->setDelegate(nullptr);
     367
     368    m_curlRequest = createCurlRequest(m_currentRequest);
     369
     370    if (protocolHostAndPortAreEqual(m_currentRequest.url(), response().url())) {
     371        auto credential = getCredential(m_currentRequest, true);
     372        m_curlRequest->setUserPass(credential.first, credential.second);
     373    }
     374
     375    m_curlRequest->start(isSyncRequest);
    290376}
    291377
  • trunk/Source/WebCore/platform/network/curl/ResourceHandleCurlDelegate.h

    r222665 r222728  
    5656    void dispatchSynchronousJob();
    5757
     58    void continueWillSendRequest(ResourceRequest&&);
     59
    5860private:
    5961    // Called from main thread.
     
    7072    void curlDidFailWithError(const ResourceError&) override;
    7173
     74    bool shouldRedirectAsGET(const ResourceRequest&, bool crossOrigin);
     75    void willSendRequest();
     76    void continueAfterWillSendRequest(ResourceRequest&&);
     77
    7278    void handleDataURL();
    7379
     
    7682    std::unique_ptr<MultipartHandle> m_multipartHandle;
    7783    unsigned m_authFailureCount { 0 };
    78     // Used by worker thread.
     84    int m_redirectCount { 0 };
     85
    7986    ResourceRequest m_firstRequest;
    8087    ResourceRequest m_currentRequest;
  • trunk/Source/WebCore/platform/network/curl/ResourceResponse.h

    r222521 r222728  
    5353    void setDeprecatedNetworkLoadMetrics(const NetworkLoadMetrics& networkLoadMetrics) { m_networkLoadMetrics = networkLoadMetrics; }
    5454
    55     bool isRedirection() const;
     55    bool shouldRedirect();
     56    bool isMovedPermanently() const;
     57    bool isFound() const;
     58    bool isSeeOther() const;
    5659    bool isNotModified() const;
    5760    bool isUnauthorized() const;
  • trunk/Source/WebCore/platform/network/curl/ResourceResponseCurl.cpp

    r222521 r222728  
    134134}
    135135
    136 bool ResourceResponse::isRedirection() const
     136bool ResourceResponse::shouldRedirect()
    137137{
    138138    auto statusCode = httpStatusCode();
    139     return (300 <= statusCode) && (statusCode < 400) && (statusCode != 304);
     139    if ((statusCode < 300) || (400 <= statusCode))
     140        return false;
     141
     142    // Some 3xx status codes aren't actually redirects.
     143    if (statusCode == 300 || statusCode == 304 || statusCode == 305 || statusCode == 306)
     144        return false;
     145
     146    if (httpHeaderField(HTTPHeaderName::Location).isEmpty())
     147        return false;
     148
     149    return true;
     150}
     151
     152bool ResourceResponse::isMovedPermanently() const
     153{
     154    return (httpStatusCode() == 301);
     155}
     156
     157bool ResourceResponse::isFound() const
     158{
     159    return (httpStatusCode() == 302);
     160}
     161
     162bool ResourceResponse::isSeeOther() const
     163{
     164    return (httpStatusCode() == 303);
    140165}
    141166
Note: See TracChangeset for help on using the changeset viewer.