Diff
Modified: trunk/Source/WebCore/ChangeLog (222727 => 222728)
--- trunk/Source/WebCore/ChangeLog 2017-10-02 18:58:07 UTC (rev 222727)
+++ trunk/Source/WebCore/ChangeLog 2017-10-02 19:00:17 UTC (rev 222728)
@@ -1,3 +1,37 @@
+2017-10-02 Basuke Suzuki <[email protected]>
+
+ [CURL] Should handle redirects in WebCore
+ https://bugs.webkit.org/show_bug.cgi?id=21242
+
+ 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.
+
2017-10-02 Antti Koivisto <[email protected]>
Crashes with guard malloc under RenderFullScreen::unwrapRenderer
Modified: trunk/Source/WebCore/platform/network/ResourceHandle.cpp (222727 => 222728)
--- trunk/Source/WebCore/platform/network/ResourceHandle.cpp 2017-10-02 18:58:07 UTC (rev 222727)
+++ trunk/Source/WebCore/platform/network/ResourceHandle.cpp 2017-10-02 19:00:17 UTC (rev 222728)
@@ -170,7 +170,7 @@
}
}
-#if !PLATFORM(COCOA) && !USE(CFURLCONNECTION) && !USE(SOUP)
+#if !PLATFORM(COCOA) && !USE(CFURLCONNECTION) && !USE(SOUP) && !USE(CURL)
// ResourceHandle never uses async client calls on these platforms yet.
void ResourceHandle::continueWillSendRequest(ResourceRequest&&)
{
Modified: trunk/Source/WebCore/platform/network/curl/CurlContext.cpp (222727 => 222728)
--- trunk/Source/WebCore/platform/network/curl/CurlContext.cpp 2017-10-02 18:58:07 UTC (rev 222727)
+++ trunk/Source/WebCore/platform/network/curl/CurlContext.cpp 2017-10-02 19:00:17 UTC (rev 222728)
@@ -425,11 +425,6 @@
curl_easy_setopt(m_handle, CURLOPT_MAXREDIRS, maxNumberOfRedirectCount);
}
-void CurlHandle::enableAutoReferer()
-{
- curl_easy_setopt(m_handle, CURLOPT_AUTOREFERER, 1L);
-}
-
void CurlHandle::enableHttpAuthentication(long option)
{
curl_easy_setopt(m_handle, CURLOPT_HTTPAUTH, option);
Modified: trunk/Source/WebCore/platform/network/curl/CurlContext.h (222727 => 222728)
--- trunk/Source/WebCore/platform/network/curl/CurlContext.h 2017-10-02 18:58:07 UTC (rev 222727)
+++ trunk/Source/WebCore/platform/network/curl/CurlContext.h 2017-10-02 19:00:17 UTC (rev 222728)
@@ -248,7 +248,6 @@
void enableAllowedProtocols();
void enableFollowLocation();
- void enableAutoReferer();
void enableHttpAuthentication(long);
void setHttpAuthUserPass(const String&, const String&);
Modified: trunk/Source/WebCore/platform/network/curl/CurlRequest.cpp (222727 => 222728)
--- trunk/Source/WebCore/platform/network/curl/CurlRequest.cpp 2017-10-02 18:58:07 UTC (rev 222727)
+++ trunk/Source/WebCore/platform/network/curl/CurlRequest.cpp 2017-10-02 19:00:17 UTC (rev 222728)
@@ -169,8 +169,6 @@
m_curlHandle->enableAcceptEncoding();
m_curlHandle->enableTimeout();
- m_curlHandle->enableAutoReferer();
- m_curlHandle->enableFollowLocation();
m_curlHandle->enableProxyIfExists();
m_curlHandle->enableCookieJarIfExists();
@@ -275,11 +273,7 @@
return receiveBytes;
}
- // If the FOLLOWLOCATION option is enabled for the curl handle then
- // curl will follow the redirections internally. Thus this header callback
- // will be called more than one time with the line starting "HTTP" for one job.
-
- m_response.url = ""
+ m_response.url = ""
m_response.statusCode = statusCode;
if (auto length = m_curlHandle->getContentLength())
@@ -308,13 +302,6 @@
auto receiveBytes = buffer->size();
- // this shouldn't be necessary but apparently is. CURL writes the data
- // of html page even if it is a redirect that was handled internally
- // can be observed e.g. on gmail.com
- auto statusCode = m_curlHandle->getResponseCode();
- if (statusCode && (300 <= *statusCode) && (*statusCode < 400))
- return receiveBytes;
-
if (receiveBytes) {
callDelegate([this, buffer = WTFMove(buffer)](CurlRequestDelegate* delegate) mutable {
if (delegate)
Modified: trunk/Source/WebCore/platform/network/curl/ResourceHandleCurl.cpp (222727 => 222728)
--- trunk/Source/WebCore/platform/network/curl/ResourceHandleCurl.cpp 2017-10-02 18:58:07 UTC (rev 222727)
+++ trunk/Source/WebCore/platform/network/curl/ResourceHandleCurl.cpp 2017-10-02 19:00:17 UTC (rev 222728)
@@ -65,6 +65,13 @@
if (d->m_context && !d->m_context->isValid())
return false;
+ // Only allow the POST and GET methods for non-HTTP requests.
+ const ResourceRequest& request = firstRequest();
+ if (!request.url().protocolIsInHTTPFamily() && request.httpMethod() != "GET" && request.httpMethod() != "POST") {
+ scheduleFailure(InvalidURLFailure); // Error must not be reported immediately
+ return true;
+ }
+
d->m_delegate = adoptRef(new ResourceHandleCurlDelegate(this));
return d->m_delegate->start();
}
@@ -250,6 +257,20 @@
response = client.response();
}
+void ResourceHandle::continueDidReceiveResponse()
+{
+ notImplemented();
+}
+
+void ResourceHandle::continueWillSendRequest(ResourceRequest&& request)
+{
+ ASSERT(isMainThread());
+ ASSERT(!client() || client()->usesAsyncCallbacks());
+
+ if (d->m_delegate)
+ d->m_delegate->continueWillSendRequest(WTFMove(request));
+}
+
} // namespace WebCore
#endif
Modified: trunk/Source/WebCore/platform/network/curl/ResourceHandleCurlDelegate.cpp (222727 => 222728)
--- trunk/Source/WebCore/platform/network/curl/ResourceHandleCurlDelegate.cpp 2017-10-02 18:58:07 UTC (rev 222727)
+++ trunk/Source/WebCore/platform/network/curl/ResourceHandleCurlDelegate.cpp 2017-10-02 19:00:17 UTC (rev 222728)
@@ -201,22 +201,9 @@
m_multipartHandle = std::make_unique<MultipartHandle>(m_handle, boundary);
}
- // HTTP redirection
- if (response().isRedirection()) {
- String location = response().httpHeaderField(HTTPHeaderName::Location);
- if (!location.isEmpty()) {
- URL newURL = URL(m_firstRequest.url(), location);
-
- ResourceRequest redirectedRequest = m_firstRequest;
- redirectedRequest.setURL(newURL);
- ResourceResponse localResponse = response();
- if (m_handle->client())
- m_handle->client()->willSendRequest(m_handle, WTFMove(redirectedRequest), WTFMove(localResponse));
-
- m_firstRequest.setURL(newURL);
-
- return;
- }
+ if (response().shouldRedirect()) {
+ willSendRequest();
+ return;
}
if (response().isUnauthorized()) {
@@ -289,6 +276,105 @@
m_handle->client()->didFail(m_handle, resourceError);
}
+bool ResourceHandleCurlDelegate::shouldRedirectAsGET(const ResourceRequest& request, bool crossOrigin)
+{
+ if ((request.httpMethod() == "GET") || (request.httpMethod() == "HEAD"))
+ return false;
+
+ if (!request.url().protocolIsInHTTPFamily())
+ return true;
+
+ if (response().isSeeOther())
+ return true;
+
+ if ((response().isMovedPermanently() || response().isFound()) && (request.httpMethod() == "POST"))
+ return true;
+
+ if (crossOrigin && (request.httpMethod() == "DELETE"))
+ return true;
+
+ return false;
+}
+
+void ResourceHandleCurlDelegate::willSendRequest()
+{
+ ASSERT(isMainThread());
+
+ static const int maxRedirects = 20;
+
+ if (m_redirectCount++ > maxRedirects) {
+ m_handle->client()->didFail(m_handle, ResourceError::httpError(CURLE_TOO_MANY_REDIRECTS, response().url()));
+ return;
+ }
+
+ String location = response().httpHeaderField(HTTPHeaderName::Location);
+ URL newURL = URL(m_firstRequest.url(), location);
+ bool crossOrigin = !protocolHostAndPortAreEqual(m_firstRequest.url(), newURL);
+
+ ResourceRequest newRequest = m_firstRequest;
+ newRequest.setURL(newURL);
+
+ if (shouldRedirectAsGET(newRequest, crossOrigin)) {
+ newRequest.setHTTPMethod("GET");
+ newRequest.setHTTPBody(nullptr);
+ newRequest.clearHTTPContentType();
+ }
+
+ // Should not set Referer after a redirect from a secure resource to non-secure one.
+ if (!newURL.protocolIs("https") && protocolIs(newRequest.httpReferrer(), "https") && m_handle->context()->shouldClearReferrerOnHTTPSToHTTPRedirect())
+ newRequest.clearHTTPReferrer();
+
+ m_user = newURL.user();
+ m_pass = newURL.pass();
+ newRequest.removeCredentials();
+
+ if (crossOrigin) {
+ // If the network layer carries over authentication headers from the original request
+ // in a cross-origin redirect, we want to clear those headers here.
+ newRequest.clearHTTPAuthorization();
+ newRequest.clearHTTPOrigin();
+ }
+
+ ResourceResponse responseCopy = response();
+ if (m_handle->client()->usesAsyncCallbacks())
+ m_handle->client()->willSendRequestAsync(m_handle, WTFMove(newRequest), WTFMove(responseCopy));
+ else {
+ auto request = m_handle->client()->willSendRequest(m_handle, WTFMove(newRequest), WTFMove(responseCopy));
+ continueAfterWillSendRequest(WTFMove(request));
+ }
+}
+
+void ResourceHandleCurlDelegate::continueWillSendRequest(ResourceRequest&& request)
+{
+ ASSERT(isMainThread());
+
+ continueAfterWillSendRequest(WTFMove(request));
+}
+
+void ResourceHandleCurlDelegate::continueAfterWillSendRequest(ResourceRequest&& request)
+{
+ ASSERT(isMainThread());
+
+ // willSendRequest might cancel the load.
+ if (cancelledOrClientless() || !m_curlRequest)
+ return;
+
+ m_currentRequest = WTFMove(request);
+
+ bool isSyncRequest = m_curlRequest->isSyncRequest();
+ m_curlRequest->cancel();
+ m_curlRequest->setDelegate(nullptr);
+
+ m_curlRequest = createCurlRequest(m_currentRequest);
+
+ if (protocolHostAndPortAreEqual(m_currentRequest.url(), response().url())) {
+ auto credential = getCredential(m_currentRequest, true);
+ m_curlRequest->setUserPass(credential.first, credential.second);
+ }
+
+ m_curlRequest->start(isSyncRequest);
+}
+
ResourceResponse& ResourceHandleCurlDelegate::response()
{
return m_handle->getInternal()->m_response;
Modified: trunk/Source/WebCore/platform/network/curl/ResourceHandleCurlDelegate.h (222727 => 222728)
--- trunk/Source/WebCore/platform/network/curl/ResourceHandleCurlDelegate.h 2017-10-02 18:58:07 UTC (rev 222727)
+++ trunk/Source/WebCore/platform/network/curl/ResourceHandleCurlDelegate.h 2017-10-02 19:00:17 UTC (rev 222728)
@@ -55,6 +55,8 @@
void dispatchSynchronousJob();
+ void continueWillSendRequest(ResourceRequest&&);
+
private:
// Called from main thread.
ResourceResponse& response();
@@ -69,6 +71,10 @@
void curlDidComplete() override;
void curlDidFailWithError(const ResourceError&) override;
+ bool shouldRedirectAsGET(const ResourceRequest&, bool crossOrigin);
+ void willSendRequest();
+ void continueAfterWillSendRequest(ResourceRequest&&);
+
void handleDataURL();
// Used by main thread.
@@ -75,7 +81,8 @@
ResourceHandle* m_handle;
std::unique_ptr<MultipartHandle> m_multipartHandle;
unsigned m_authFailureCount { 0 };
- // Used by worker thread.
+ int m_redirectCount { 0 };
+
ResourceRequest m_firstRequest;
ResourceRequest m_currentRequest;
bool m_shouldUseCredentialStorage;
Modified: trunk/Source/WebCore/platform/network/curl/ResourceResponse.h (222727 => 222728)
--- trunk/Source/WebCore/platform/network/curl/ResourceResponse.h 2017-10-02 18:58:07 UTC (rev 222727)
+++ trunk/Source/WebCore/platform/network/curl/ResourceResponse.h 2017-10-02 19:00:17 UTC (rev 222728)
@@ -52,7 +52,10 @@
void setDeprecatedNetworkLoadMetrics(const NetworkLoadMetrics& networkLoadMetrics) { m_networkLoadMetrics = networkLoadMetrics; }
- bool isRedirection() const;
+ bool shouldRedirect();
+ bool isMovedPermanently() const;
+ bool isFound() const;
+ bool isSeeOther() const;
bool isNotModified() const;
bool isUnauthorized() const;
Modified: trunk/Source/WebCore/platform/network/curl/ResourceResponseCurl.cpp (222727 => 222728)
--- trunk/Source/WebCore/platform/network/curl/ResourceResponseCurl.cpp 2017-10-02 18:58:07 UTC (rev 222727)
+++ trunk/Source/WebCore/platform/network/curl/ResourceResponseCurl.cpp 2017-10-02 19:00:17 UTC (rev 222728)
@@ -133,12 +133,37 @@
return filenameFromHTTPContentDisposition(httpHeaderField(HTTPHeaderName::ContentDisposition));
}
-bool ResourceResponse::isRedirection() const
+bool ResourceResponse::shouldRedirect()
{
auto statusCode = httpStatusCode();
- return (300 <= statusCode) && (statusCode < 400) && (statusCode != 304);
+ if ((statusCode < 300) || (400 <= statusCode))
+ return false;
+
+ // Some 3xx status codes aren't actually redirects.
+ if (statusCode == 300 || statusCode == 304 || statusCode == 305 || statusCode == 306)
+ return false;
+
+ if (httpHeaderField(HTTPHeaderName::Location).isEmpty())
+ return false;
+
+ return true;
}
+bool ResourceResponse::isMovedPermanently() const
+{
+ return (httpStatusCode() == 301);
+}
+
+bool ResourceResponse::isFound() const
+{
+ return (httpStatusCode() == 302);
+}
+
+bool ResourceResponse::isSeeOther() const
+{
+ return (httpStatusCode() == 303);
+}
+
bool ResourceResponse::isNotModified() const
{
return (httpStatusCode() == 304);