Changeset 222665 in webkit
- Timestamp:
- Sep 29, 2017 2:19:32 PM (6 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 3 added
- 5 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r222664 r222665 1 2017-09-29 Basuke Suzuki <Basuke.Suzuki@sony.com> 2 3 [Curl] Extract a features to manage HTTP communication from ResourceHandle 4 https://bugs.webkit.org/show_bug.cgi?id=175148 5 6 Reviewed by Alex Christensen. 7 8 * platform/Curl.cmake: 9 * platform/network/curl/CurlRequest.cpp: Added. 10 (WebCore::CurlRequest::CurlRequest): 11 (WebCore::CurlRequest::setUserPass): 12 (WebCore::CurlRequest::start): 13 (WebCore::CurlRequest::startWithJobManager): 14 (WebCore::CurlRequest::cancel): 15 (WebCore::CurlRequest::suspend): 16 (WebCore::CurlRequest::resume): 17 (WebCore::CurlRequest::callDelegate): 18 (WebCore::CurlRequest::setupTransfer): 19 (WebCore::CurlRequest::willSetupSslCtx): 20 (WebCore::CurlRequest::willSendData): 21 (WebCore::CurlRequest::didReceiveHeader): 22 (WebCore::CurlRequest::didReceiveData): 23 (WebCore::CurlRequest::didCompleteTransfer): 24 (WebCore::CurlRequest::didCancelTransfer): 25 (WebCore::CurlRequest::resolveBlobReferences): 26 (WebCore::CurlRequest::setupPUT): 27 (WebCore::CurlRequest::setupPOST): 28 (WebCore::CurlRequest::setupFormData): 29 (WebCore::CurlRequest::invokeDidReceiveResponseForFile): 30 (WebCore::CurlRequest::invokeDidReceiveResponse): 31 (WebCore::CurlRequest::setPaused): 32 (WebCore::CurlRequest::willSetupSslCtxCallback): 33 (WebCore::CurlRequest::willSendDataCallback): 34 (WebCore::CurlRequest::didReceiveHeaderCallback): 35 (WebCore::CurlRequest::didReceiveDataCallback): 36 * platform/network/curl/CurlRequest.h: Added. 37 (WebCore::CurlRequest::~CurlRequest): 38 (WebCore::CurlRequest::setDelegate): 39 (WebCore::CurlRequest::isSyncRequest): 40 (WebCore::CurlRequest::getNetworkLoadMetrics): 41 * platform/network/curl/CurlRequestDelegate.h: Added. 42 * platform/network/curl/ResourceHandleCurl.cpp: 43 (WebCore::ResourceHandle::cancel): 44 (WebCore::ResourceHandle::platformSetDefersLoading): 45 (WebCore::ResourceHandle::didReceiveAuthenticationChallenge): 46 (WebCore::ResourceHandle::receivedCredential): 47 (WebCore::ResourceHandle::receivedRequestToContinueWithoutCredential): 48 (WebCore::ResourceHandle::receivedCancellation): 49 * platform/network/curl/ResourceHandleCurlDelegate.cpp: 50 (WebCore::ResourceHandleCurlDelegate::ResourceHandleCurlDelegate): 51 (WebCore::ResourceHandleCurlDelegate::~ResourceHandleCurlDelegate): 52 (WebCore::ResourceHandleCurlDelegate::start): 53 (WebCore::ResourceHandleCurlDelegate::cancel): 54 (WebCore::ResourceHandleCurlDelegate::setDefersLoading): 55 (WebCore::ResourceHandleCurlDelegate::setAuthentication): 56 (WebCore::ResourceHandleCurlDelegate::dispatchSynchronousJob): 57 (WebCore::ResourceHandleCurlDelegate::createCurlRequest): 58 (WebCore::ResourceHandleCurlDelegate::cancelledOrClientless): 59 (WebCore::ResourceHandleCurlDelegate::curlDidReceiveResponse): 60 (WebCore::ResourceHandleCurlDelegate::curlDidReceiveBuffer): 61 (WebCore::ResourceHandleCurlDelegate::curlDidComplete): 62 (WebCore::ResourceHandleCurlDelegate::curlDidFailWithError): 63 (WebCore::ResourceHandleCurlDelegate::response): 64 (WebCore::ResourceHandleCurlDelegate::getCredential): 65 (WebCore::ResourceHandleCurlDelegate::retain): Deleted. 66 (WebCore::ResourceHandleCurlDelegate::release): Deleted. 67 (WebCore::ResourceHandleCurlDelegate::setupTransfer): Deleted. 68 (WebCore::ResourceHandleCurlDelegate::didCompleteTransfer): Deleted. 69 (WebCore::ResourceHandleCurlDelegate::didCancelTransfer): Deleted. 70 (WebCore::ResourceHandleCurlDelegate::setupAuthentication): Deleted. 71 (WebCore::ResourceHandleCurlDelegate::didReceiveAllHeaders): Deleted. 72 (WebCore::ResourceHandleCurlDelegate::didReceiveContentData): Deleted. 73 (WebCore::ResourceHandleCurlDelegate::handleLocalReceiveResponse): Deleted. 74 (WebCore::ResourceHandleCurlDelegate::prepareSendData): Deleted. 75 (WebCore::ResourceHandleCurlDelegate::didFinish): Deleted. 76 (WebCore::ResourceHandleCurlDelegate::didFail): Deleted. 77 (WebCore::ResourceHandleCurlDelegate::setupPOST): Deleted. 78 (WebCore::ResourceHandleCurlDelegate::setupPUT): Deleted. 79 (WebCore::ResourceHandleCurlDelegate::getFormElementsCount): Deleted. 80 (WebCore::ResourceHandleCurlDelegate::setupFormData): Deleted. 81 (WebCore::ResourceHandleCurlDelegate::applyAuthentication): Deleted. 82 (WebCore::ResourceHandleCurlDelegate::getNetworkLoadMetrics): Deleted. 83 (WebCore::ResourceHandleCurlDelegate::willSetupSslCtx): Deleted. 84 (WebCore::ResourceHandleCurlDelegate::didReceiveHeader): Deleted. 85 (WebCore::ResourceHandleCurlDelegate::didReceiveData): Deleted. 86 (WebCore::ResourceHandleCurlDelegate::willSendData): Deleted. 87 (WebCore::ResourceHandleCurlDelegate::willSetupSslCtxCallback): Deleted. 88 (WebCore::ResourceHandleCurlDelegate::didReceiveHeaderCallback): Deleted. 89 (WebCore::ResourceHandleCurlDelegate::didReceiveDataCallback): Deleted. 90 (WebCore::ResourceHandleCurlDelegate::willSendDataCallback): Deleted. 91 * platform/network/curl/ResourceHandleCurlDelegate.h: 92 1 93 2017-09-29 Chris Dumez <cdumez@apple.com> 2 94 -
trunk/Source/WebCore/platform/Curl.cmake
r222223 r222665 12 12 platform/network/curl/CurlDownload.cpp 13 13 platform/network/curl/CurlJobManager.cpp 14 platform/network/curl/CurlRequest.cpp 14 15 platform/network/curl/CurlSSLHandle.cpp 15 16 platform/network/curl/CurlSSLVerifier.cpp -
trunk/Source/WebCore/platform/network/curl/ResourceHandleCurl.cpp
r222467 r222665 33 33 #if USE(CURL) 34 34 35 #include "CachedResourceLoader.h"36 35 #include "CredentialStorage.h" 37 #include "CurlCacheManager.h"38 36 #include "CurlContext.h" 39 #include "CurlJobManager.h"40 #include "CurlSSLHandle.h"41 37 #include "FileSystem.h" 42 38 #include "Logging.h" 43 #include "MIMETypeRegistry.h"44 #include "NetworkingContext.h"45 39 #include "ResourceHandleInternal.h" 46 40 #include "SynchronousLoaderClient.h" 47 #include <wtf/text/Base64.h>48 41 49 42 namespace WebCore { … … 79 72 void ResourceHandle::cancel() 80 73 { 81 d->m_delegate->cancel(); 74 if (d->m_delegate) 75 d->m_delegate->cancel(); 82 76 } 83 77 … … 115 109 ASSERT(isMainThread()); 116 110 117 d->m_delegate->setDefersLoading(defers); 111 if (d->m_delegate) 112 d->m_delegate->setDefersLoading(defers); 118 113 } 119 114 … … 137 132 CredentialStorage::defaultCredentialStorage().set(partition, credential, challenge.protectionSpace(), urlToStore); 138 133 139 d->m_delegate->setAuthentication(credential.user(), credential.password()); 134 if (d->m_delegate) 135 d->m_delegate->setAuthentication(credential.user(), credential.password()); 140 136 141 137 d->m_user = String(); … … 162 158 } 163 159 164 d->m_delegate->setAuthentication(credential.user(), credential.password()); 160 if (d->m_delegate) 161 d->m_delegate->setAuthentication(credential.user(), credential.password()); 165 162 return; 166 163 } … … 169 166 170 167 d->m_currentWebChallenge = challenge; 171 172 if (client()) 168 169 if (client()) { 170 auto protectedThis = makeRef(*this); 173 171 client()->didReceiveAuthenticationChallenge(this, d->m_currentWebChallenge); 172 } 174 173 } 175 174 … … 195 194 } 196 195 197 d->m_delegate->setAuthentication(credential.user(), credential.password()); 196 if (d->m_delegate) 197 d->m_delegate->setAuthentication(credential.user(), credential.password()); 198 198 199 clearAuthentication(); 199 200 } … … 206 207 return; 207 208 208 d->m_delegate->setAuthentication("", ""); 209 if (d->m_delegate) 210 d->m_delegate->setAuthentication("", ""); 211 209 212 clearAuthentication(); 210 213 } … … 217 220 return; 218 221 219 if (client()) 222 if (client()) { 223 auto protectedThis = makeRef(*this); 220 224 client()->receivedCancellation(this, challenge); 225 } 221 226 } 222 227 -
trunk/Source/WebCore/platform/network/curl/ResourceHandleCurlDelegate.cpp
r222521 r222665 33 33 #if USE(CURL) 34 34 35 #include "AuthenticationChallenge.h" 35 36 #include "CredentialStorage.h" 36 37 #include "CurlCacheManager.h" 38 #include "CurlRequest.h" 37 39 #include "HTTPParsers.h" 38 #include "MIMETypeRegistry.h"39 40 #include "MultipartHandle.h" 40 #include "ResourceHandle.h"41 41 #include "ResourceHandleInternal.h" 42 42 #include "SharedBuffer.h" 43 43 #include "TextEncoding.h" 44 #include "URL.h"45 #include <wtf/MainThread.h>46 44 #include <wtf/text/Base64.h> 47 45 … … 51 49 : m_handle(handle) 52 50 , m_firstRequest(handle->firstRequest().isolatedCopy()) 53 , m_cu stomHTTPHeaderFields(m_firstRequest.httpHeaderFields().isolatedCopy())51 , m_currentRequest(handle->firstRequest().isolatedCopy()) 54 52 , m_shouldUseCredentialStorage(handle->shouldUseCredentialStorage()) 55 53 , m_user(handle->getInternal()->m_user.isolatedCopy()) … … 58 56 , m_defersLoading(handle->getInternal()->m_defersLoading) 59 57 { 60 const URL& url = m_firstRequest.url(); 61 62 if (m_customHTTPHeaderFields.size()) { 63 auto& cache = CurlCacheManager::getInstance(); 64 bool hasCacheHeaders = m_customHTTPHeaderFields.contains(HTTPHeaderName::IfModifiedSince) || m_customHTTPHeaderFields.contains(HTTPHeaderName::IfNoneMatch); 65 if (!hasCacheHeaders && cache.isCached(url)) { 66 cache.addCacheEntryClient(url, m_handle); 67 // append additional cache information 68 for (auto entry : cache.requestHeaders(url)) 69 m_customHTTPHeaderFields.set(entry.key, entry.value); 70 m_addedCacheValidationHeaders = true; 71 } 72 } 73 74 setupAuthentication(); 58 75 59 } 76 60 77 61 ResourceHandleCurlDelegate::~ResourceHandleCurlDelegate() 78 62 { 63 if (m_curlRequest) 64 m_curlRequest->setDelegate(nullptr); 79 65 } 80 66 … … 89 75 } 90 76 91 void ResourceHandleCurlDelegate::start(bool isSyncRequest) 92 { 93 m_isSyncRequest = isSyncRequest; 94 95 if (!m_isSyncRequest) { 96 // For asynchronous, use CurlJobManager. Curl processes runs on sub thread. 97 CurlJobManager::singleton().add(this); 98 } else { 99 // For synchronous, does not use CurlJobManager. Curl processes runs on main thread. 100 retain(); 101 setupTransfer(); 102 103 // curl_easy_perform blocks until the transfer is finished. 104 CURLcode resultCode = m_curlHandle->perform(); 105 didCompleteTransfer(resultCode); 106 release(); 107 } 77 bool ResourceHandleCurlDelegate::start() 78 { 79 ASSERT(isMainThread()); 80 81 auto credential = getCredential(m_currentRequest, false); 82 83 m_curlRequest = createCurlRequest(m_currentRequest); 84 m_curlRequest->setUserPass(credential.first, credential.second); 85 m_curlRequest->start(); 86 87 return true; 108 88 } 109 89 110 90 void ResourceHandleCurlDelegate::cancel() 111 91 { 92 ASSERT(isMainThread()); 93 112 94 releaseHandle(); 113 95 114 if (!m_ isSyncRequest)115 CurlJobManager::singleton().cancel(this);96 if (!m_curlRequest) 97 m_curlRequest->cancel(); 116 98 } 117 99 118 100 void ResourceHandleCurlDelegate::setDefersLoading(bool defers) 119 101 { 102 ASSERT(isMainThread()); 103 120 104 if (defers == m_defersLoading) 121 105 return; … … 123 107 m_defersLoading = defers; 124 108 125 auto action = [protectedThis = makeRef(*this)]() { 126 if (!protectedThis->m_curlHandle) 127 return; 128 129 if (protectedThis->m_defersLoading) { 130 CURLcode error = protectedThis->m_curlHandle->pause(CURLPAUSE_ALL); 131 // If we could not defer the handle, so don't do it. 132 if (error != CURLE_OK) 133 return; 134 } else { 135 CURLcode error = protectedThis->m_curlHandle->pause(CURLPAUSE_CONT); 136 if (error != CURLE_OK) { 137 // Restarting the handle has failed so just cancel it. 138 protectedThis->m_handle->cancel(); 139 } 140 } 141 }; 142 143 CurlJobManager::singleton().callOnJobThread(WTFMove(action)); 144 } 145 146 void ResourceHandleCurlDelegate::setAuthentication(const String& user, const String& pass) 147 { 148 auto action = [protectedThis = makeRef(*this), user = user.isolatedCopy(), pass = pass.isolatedCopy()]() { 149 protectedThis->m_user = user; 150 protectedThis->m_pass = pass; 151 if (protectedThis->m_curlHandle) 152 protectedThis->m_curlHandle->setHttpAuthUserPass(user, pass); 153 }; 154 155 CurlJobManager::singleton().callOnJobThread(WTFMove(action)); 109 if (!m_curlRequest) 110 return; 111 112 if (m_defersLoading) 113 m_curlRequest->suspend(); 114 else 115 m_curlRequest->resume(); 116 } 117 118 void ResourceHandleCurlDelegate::setAuthentication(const String& user, const String& password) 119 { 120 ASSERT(isMainThread()); 121 122 if (!m_curlRequest) 123 return; 124 125 bool isSyncRequest = m_curlRequest->isSyncRequest(); 126 m_curlRequest->cancel(); 127 m_curlRequest->setDelegate(nullptr); 128 129 m_curlRequest = createCurlRequest(m_currentRequest); 130 m_curlRequest->setUserPass(user, password); 131 m_curlRequest->start(isSyncRequest); 156 132 } 157 133 158 134 void ResourceHandleCurlDelegate::dispatchSynchronousJob() 159 135 { 160 if (m_ firstRequest.url().protocolIsData()) {136 if (m_currentRequest.url().protocolIsData()) { 161 137 handleDataURL(); 162 138 return; … … 168 144 m_defersLoading = false; 169 145 170 start(true); 171 } 172 173 void ResourceHandleCurlDelegate::retain() 174 { 175 ref(); 176 } 177 178 void ResourceHandleCurlDelegate::release() 179 { 180 deref(); 181 } 182 183 CURL* ResourceHandleCurlDelegate::setupTransfer() 184 { 185 m_curlHandle = std::make_unique<CurlHandle>(); 186 m_curlHandle->initialize(); 187 188 if (m_defersLoading) { 189 CURLcode error = m_curlHandle->pause(CURLPAUSE_ALL); 190 // If we did not pause the handle, we would ASSERT in the 191 // header callback. So just assert here. 192 ASSERT_UNUSED(error, error == CURLE_OK); 193 } 194 195 #ifndef NDEBUG 196 m_curlHandle->enableVerboseIfUsed(); 197 m_curlHandle->enableStdErrIfUsed(); 198 #endif 199 200 auto& sslHandle = CurlContext::singleton().sslHandle(); 201 202 m_curlHandle->setSslVerifyPeer(CurlHandle::VerifyPeer::Enable); 203 m_curlHandle->setSslVerifyHost(CurlHandle::VerifyHost::StrictNameCheck); 204 m_curlHandle->setWriteCallbackFunction(didReceiveDataCallback, this); 205 m_curlHandle->setHeaderCallbackFunction(didReceiveHeaderCallback, this); 206 m_curlHandle->enableAutoReferer(); 207 m_curlHandle->enableFollowLocation(); 208 m_curlHandle->enableHttpAuthentication(CURLAUTH_ANY); 209 m_curlHandle->enableShareHandle(); 210 m_curlHandle->enableTimeout(); 211 m_curlHandle->enableAllowedProtocols(); 212 213 auto sslClientCertificate = sslHandle.getSSLClientCertificate(m_firstRequest.url().host()); 214 if (sslClientCertificate) { 215 m_curlHandle->setSslCert(sslClientCertificate->first.utf8().data()); 216 m_curlHandle->setSslCertType("P12"); 217 m_curlHandle->setSslKeyPassword(sslClientCertificate->second.utf8().data()); 218 } 219 220 if (sslHandle.shouldIgnoreSSLErrors()) 221 m_curlHandle->setSslVerifyPeer(CurlHandle::VerifyPeer::Disable); 222 else 223 m_curlHandle->setSslCtxCallbackFunction(willSetupSslCtxCallback, this); 224 225 m_curlHandle->setCACertPath(sslHandle.getCACertPath()); 226 227 m_curlHandle->enableAcceptEncoding(); 228 m_curlHandle->setUrl(m_firstRequest.url()); 229 m_curlHandle->enableCookieJarIfExists(); 230 231 if (m_customHTTPHeaderFields.size()) 232 m_curlHandle->appendRequestHeaders(m_customHTTPHeaderFields); 233 234 String method = m_firstRequest.httpMethod(); 235 if ("GET" == method) 236 m_curlHandle->enableHttpGetRequest(); 237 else if ("POST" == method) 238 setupPOST(); 239 else if ("PUT" == method) 240 setupPUT(); 241 else if ("HEAD" == method) 242 m_curlHandle->enableHttpHeadRequest(); 243 else { 244 m_curlHandle->setHttpCustomRequest(method); 245 setupPUT(); 246 } 247 248 applyAuthentication(); 249 250 m_curlHandle->enableProxyIfExists(); 251 252 return m_curlHandle->handle(); 253 } 254 255 void ResourceHandleCurlDelegate::didCompleteTransfer(CURLcode result) 256 { 257 if (result == CURLE_OK) { 258 NetworkLoadMetrics networkLoadMetrics = getNetworkLoadMetrics(); 259 260 if (isMainThread()) 261 didFinish(networkLoadMetrics); 262 else { 263 callOnMainThread([protectedThis = makeRef(*this), metrics = networkLoadMetrics.isolatedCopy()] { 264 if (!protectedThis->m_handle) 265 return; 266 protectedThis->didFinish(metrics); 267 }); 268 } 269 } else { 270 ResourceError resourceError = ResourceError::httpError(result, m_firstRequest.url()); 271 if (m_sslVerifier.sslErrors()) 272 resourceError.setSslErrors(m_sslVerifier.sslErrors()); 273 274 if (isMainThread()) 275 didFail(resourceError); 276 else { 277 callOnMainThread([protectedThis = makeRef(*this), error = resourceError.isolatedCopy()] { 278 if (!protectedThis->m_handle) 279 return; 280 protectedThis->didFail(error); 281 }); 282 } 283 } 284 285 m_formDataStream = nullptr; 286 m_curlHandle = nullptr; 287 } 288 289 void ResourceHandleCurlDelegate::didCancelTransfer() 290 { 291 m_formDataStream = nullptr; 292 m_curlHandle = nullptr; 293 } 294 295 ResourceResponse& ResourceHandleCurlDelegate::response() 296 { 297 return m_handle->getInternal()->m_response; 298 } 299 300 void ResourceHandleCurlDelegate::setupAuthentication() 301 { 302 // m_user/m_pass are credentials given manually, for instance, by the arguments passed to XMLHttpRequest.open(). 303 String partition = m_firstRequest.cachePartition(); 304 305 if (m_shouldUseCredentialStorage) { 306 if (m_user.isEmpty() && m_pass.isEmpty()) { 307 // <rdar://problem/7174050> - For URLs that match the paths of those previously challenged for HTTP Basic authentication, 308 // try and reuse the credential preemptively, as allowed by RFC 2617. 309 m_initialCredential = CredentialStorage::defaultCredentialStorage().get(partition, m_firstRequest.url()); 310 } else { 311 // If there is already a protection space known for the URL, update stored credentials 312 // before sending a request. This makes it possible to implement logout by sending an 313 // XMLHttpRequest with known incorrect credentials, and aborting it immediately (so that 314 // an authentication dialog doesn't pop up). 315 CredentialStorage::defaultCredentialStorage().set(partition, Credential(m_user, m_pass, CredentialPersistenceNone), m_firstRequest.url()); 316 } 317 } 318 } 319 320 void ResourceHandleCurlDelegate::didReceiveAllHeaders(const CurlResponse& receivedResponse) 321 { 322 ASSERT(isMainThread()); 146 m_curlRequest = createCurlRequest(m_currentRequest); 147 m_curlRequest->start(true); 148 } 149 150 RefPtr<CurlRequest> ResourceHandleCurlDelegate::createCurlRequest(ResourceRequest& request) 151 { 152 ASSERT(isMainThread()); 153 154 // CurlCache : append additional cache information 155 m_addedCacheValidationHeaders = false; 156 157 bool hasCacheHeaders = request.httpHeaderFields().contains(HTTPHeaderName::IfModifiedSince) || request.httpHeaderFields().contains(HTTPHeaderName::IfNoneMatch); 158 if (!hasCacheHeaders) { 159 auto& cache = CurlCacheManager::getInstance(); 160 URL cacheUrl = request.url(); 161 cacheUrl.removeFragmentIdentifier(); 162 163 if (cache.isCached(cacheUrl)) { 164 cache.addCacheEntryClient(cacheUrl, m_handle); 165 166 for (auto entry : cache.requestHeaders(cacheUrl)) 167 request.addHTTPHeaderField(entry.key, entry.value); 168 169 m_addedCacheValidationHeaders = true; 170 } 171 } 172 173 return adoptRef(new CurlRequest(request, this, m_defersLoading)); 174 } 175 176 bool ResourceHandleCurlDelegate::cancelledOrClientless() 177 { 178 if (!m_handle) 179 return true; 180 181 return !m_handle->client(); 182 } 183 184 void ResourceHandleCurlDelegate::curlDidReceiveResponse(const CurlResponse& receivedResponse) 185 { 186 ASSERT(isMainThread()); 187 ASSERT(!m_defersLoading); 188 189 if (cancelledOrClientless()) 190 return; 323 191 324 192 m_handle->getInternal()->m_response = ResourceResponse(receivedResponse); 193 194 if (m_curlRequest) 195 m_handle->getInternal()->m_response.setDeprecatedNetworkLoadMetrics(m_curlRequest->getNetworkLoadMetrics()); 325 196 326 197 if (response().isMultipart()) { … … 347 218 return; 348 219 } 349 } else if (response().isUnauthorized()) { 220 } 221 222 if (response().isUnauthorized()) { 350 223 AuthenticationChallenge challenge(receivedResponse, m_authFailureCount, response(), m_handle); 351 224 m_handle->didReceiveAuthenticationChallenge(challenge); … … 354 227 } 355 228 356 m_didNotifyResponse = true;357 358 229 if (m_handle->client()) { 359 230 if (response().isNotModified()) { 360 const String& url = m_firstRequest.url().string(); 361 if (CurlCacheManager::getInstance().getCachedResponse(url, response())) { 231 URL cacheUrl = m_currentRequest.url(); 232 cacheUrl.removeFragmentIdentifier(); 233 234 if (CurlCacheManager::getInstance().getCachedResponse(cacheUrl, response())) { 362 235 if (m_addedCacheValidationHeaders) { 363 236 response().setHTTPStatusCode(200); … … 366 239 } 367 240 } 241 368 242 CurlCacheManager::getInstance().didReceiveResponse(*m_handle, response()); 369 243 m_handle->client()->didReceiveResponse(m_handle, ResourceResponse(response())); … … 371 245 } 372 246 373 void ResourceHandleCurlDelegate:: didReceiveContentData(Ref<SharedBuffer>&& buffer)374 { 375 ASSERT(isMainThread()); 376 377 if ( !m_didNotifyResponse)378 handleLocalReceiveResponse();247 void ResourceHandleCurlDelegate::curlDidReceiveBuffer(Ref<SharedBuffer>&& buffer) 248 { 249 ASSERT(isMainThread()); 250 251 if (cancelledOrClientless()) 252 return; 379 253 380 254 if (m_multipartHandle) … … 386 260 } 387 261 388 void ResourceHandleCurlDelegate::handleLocalReceiveResponse() 389 { 390 ASSERT(isMainThread()); 391 392 // since the code in headerCallback will not have run for local files 393 // the code to set the URL and fire didReceiveResponse is never run, 394 // which means the ResourceLoader's response does not contain the URL. 395 // Run the code here for local files to resolve the issue. 396 // TODO: See if there is a better approach for handling this. 397 URL url = m_curlHandle->getEffectiveURL(); 398 ASSERT(url.isValid()); 399 response().setURL(url); 400 401 // Determine the MIME type based on the path. 402 response().setMimeType(MIMETypeRegistry::getMIMETypeForPath(url)); 403 404 m_didNotifyResponse = true; 405 406 if (m_handle->client()) 407 m_handle->client()->didReceiveResponse(m_handle, ResourceResponse(response())); 408 } 409 410 void ResourceHandleCurlDelegate::prepareSendData(char* buffer, size_t blockSize, size_t numberOfBlocks) 411 { 412 ASSERT(isMainThread()); 413 ASSERT(!m_sendBytes); 414 415 std::unique_lock<Lock> lock(m_workerThreadMutex); 416 417 if (!m_formDataStream || !m_formDataStream->hasMoreElements()) { 418 m_workerThreadConditionVariable.notifyOne(); 419 return; 420 } 421 422 size_t size = m_formDataStream->read(buffer, blockSize, numberOfBlocks); 423 if (!size) { 424 // Something went wrong so cancel the job. 425 m_handle->cancel(); 426 m_workerThreadConditionVariable.notifyOne(); 427 return; 428 } 429 430 m_sendBytes = size; 431 m_workerThreadConditionVariable.notifyOne(); 432 } 433 434 void ResourceHandleCurlDelegate::didFinish(NetworkLoadMetrics networkLoadMetrics) 435 { 436 response().setDeprecatedNetworkLoadMetrics(networkLoadMetrics); 437 438 if (!m_handle) 439 return; 440 441 if (!m_didNotifyResponse) { 442 handleLocalReceiveResponse(); 443 if (!m_handle) 444 return; 445 } 262 void ResourceHandleCurlDelegate::curlDidComplete() 263 { 264 ASSERT(isMainThread()); 265 266 if (cancelledOrClientless()) 267 return; 268 269 if (m_curlRequest) 270 m_handle->getInternal()->m_response.setDeprecatedNetworkLoadMetrics(m_curlRequest->getNetworkLoadMetrics()); 446 271 447 272 if (m_multipartHandle) … … 454 279 } 455 280 456 void ResourceHandleCurlDelegate::didFail(const ResourceError& resourceError) 457 { 458 if (!m_handle) 459 return; 460 461 if (m_handle->client()) { 462 CurlCacheManager::getInstance().didFail(*m_handle); 463 m_handle->client()->didFail(m_handle, resourceError); 464 } 281 void ResourceHandleCurlDelegate::curlDidFailWithError(const ResourceError& resourceError) 282 { 283 ASSERT(isMainThread()); 284 285 if (cancelledOrClientless()) 286 return; 287 288 CurlCacheManager::getInstance().didFail(*m_handle); 289 m_handle->client()->didFail(m_handle, resourceError); 290 } 291 292 ResourceResponse& ResourceHandleCurlDelegate::response() 293 { 294 return m_handle->getInternal()->m_response; 465 295 } 466 296 … … 527 357 } 528 358 529 void ResourceHandleCurlDelegate::setupPOST() 530 { 531 m_curlHandle->enableHttpPostRequest(); 532 533 size_t numElements = getFormElementsCount(); 534 if (!numElements) 535 return; 536 537 // Do not stream for simple POST data 538 if (numElements == 1) { 539 m_postBytes = m_firstRequest.httpBody()->flatten(); 540 if (m_postBytes.size()) 541 m_curlHandle->setPostFields(m_postBytes.data(), m_postBytes.size()); 542 return; 543 } 544 545 setupFormData(true); 546 } 547 548 void ResourceHandleCurlDelegate::setupPUT() 549 { 550 m_curlHandle->enableHttpPutRequest(); 551 552 // Disable the Expect: 100 continue header 553 m_curlHandle->removeRequestHeader("Expect"); 554 555 size_t numElements = getFormElementsCount(); 556 if (!numElements) 557 return; 558 559 setupFormData(false); 560 } 561 562 size_t ResourceHandleCurlDelegate::getFormElementsCount() 563 { 564 RefPtr<FormData> formData = m_firstRequest.httpBody(); 565 if (!formData) 566 return 0; 567 568 // Resolve the blob elements so the formData can correctly report it's size. 569 formData = formData->resolveBlobReferences(); 570 size_t size = formData->elements().size(); 571 m_firstRequest.setHTTPBody(WTFMove(formData)); 572 return size; 573 } 574 575 void ResourceHandleCurlDelegate::setupFormData(bool isPostRequest) 576 { 577 Vector<FormDataElement> elements = m_firstRequest.httpBody()->elements(); 578 size_t numElements = elements.size(); 579 580 static const long long maxCurlOffT = m_curlHandle->maxCurlOffT(); 581 582 // Obtain the total size of the form data 583 curl_off_t size = 0; 584 bool chunkedTransfer = false; 585 for (size_t i = 0; i < numElements; i++) { 586 FormDataElement element = elements[i]; 587 if (element.m_type == FormDataElement::Type::EncodedFile) { 588 long long fileSizeResult; 589 if (getFileSize(element.m_filename, fileSizeResult)) { 590 if (fileSizeResult > maxCurlOffT) { 591 // File size is too big for specifying it to cURL 592 chunkedTransfer = true; 593 break; 594 } 595 size += fileSizeResult; 596 } else { 597 chunkedTransfer = true; 598 break; 599 } 600 } else 601 size += elements[i].m_data.size(); 602 } 603 604 // cURL guesses that we want chunked encoding as long as we specify the header 605 if (chunkedTransfer) 606 m_curlHandle->appendRequestHeader("Transfer-Encoding: chunked"); 607 else { 608 if (isPostRequest) 609 m_curlHandle->setPostFieldLarge(size); 610 else 611 m_curlHandle->setInFileSizeLarge(size); 612 } 613 614 m_formDataStream = std::make_unique<FormDataStream>(); 615 m_formDataStream->setHTTPBody(m_firstRequest.httpBody()); 616 617 m_curlHandle->setReadCallbackFunction(willSendDataCallback, this); 618 } 619 620 void ResourceHandleCurlDelegate::applyAuthentication() 621 { 359 std::pair<String, String> ResourceHandleCurlDelegate::getCredential(ResourceRequest& request, bool redirect) 360 { 361 // m_user/m_pass are credentials given manually, for instance, by the arguments passed to XMLHttpRequest.open(). 362 String partition = request.cachePartition(); 363 364 if (m_shouldUseCredentialStorage) { 365 if (m_user.isEmpty() && m_pass.isEmpty()) { 366 // <rdar://problem/7174050> - For URLs that match the paths of those previously challenged for HTTP Basic authentication, 367 // try and reuse the credential preemptively, as allowed by RFC 2617. 368 m_initialCredential = CredentialStorage::defaultCredentialStorage().get(partition, request.url()); 369 } else if (!redirect) { 370 // If there is already a protection space known for the URL, update stored credentials 371 // before sending a request. This makes it possible to implement logout by sending an 372 // XMLHttpRequest with known incorrect credentials, and aborting it immediately (so that 373 // an authentication dialog doesn't pop up). 374 CredentialStorage::defaultCredentialStorage().set(partition, Credential(m_user, m_pass, CredentialPersistenceNone), request.url()); 375 } 376 } 377 622 378 String user = m_user; 623 379 String password = m_pass; … … 626 382 user = m_initialCredential.user(); 627 383 password = m_initialCredential.password(); 628 m_curlHandle->enableHttpAuthentication(CURLAUTH_BASIC); 629 } 630 631 // It seems we need to set CURLOPT_USERPWD even if username and password is empty. 632 // Otherwise cURL will not automatically continue with a new request after a 401 response. 633 634 // curl CURLOPT_USERPWD expects username:password 635 m_curlHandle->setHttpAuthUserPass(user, password); 636 } 637 638 NetworkLoadMetrics ResourceHandleCurlDelegate::getNetworkLoadMetrics() 639 { 640 NetworkLoadMetrics networkLoadMetrics; 641 if (auto metrics = m_curlHandle->getNetworkLoadMetrics()) 642 networkLoadMetrics = *metrics; 643 644 return networkLoadMetrics; 645 } 646 647 CURLcode ResourceHandleCurlDelegate::willSetupSslCtx(void* sslCtx) 648 { 649 m_sslVerifier.setCurlHandle(m_curlHandle.get()); 650 m_sslVerifier.setHostName(m_firstRequest.url().host()); 651 m_sslVerifier.setSslCtx(sslCtx); 652 653 return CURLE_OK; 654 } 655 656 /* 657 * This is being called for each HTTP header in the response. This includes '\r\n' 658 * for the last line of the header. 659 * 660 * We will add each HTTP Header to the ResourceResponse and on the termination 661 * of the header (\r\n) we will parse Content-Type and Content-Disposition and 662 * update the ResourceResponse and then send it away. 663 * 664 */ 665 size_t ResourceHandleCurlDelegate::didReceiveHeader(String&& header) 666 { 667 static const auto emptyLineCRLF = "\r\n"; 668 static const auto emptyLineLF = "\n"; 669 670 if (!m_handle) 671 return 0; 672 673 if (m_defersLoading) 674 return 0; 675 676 size_t receiveBytes = header.length(); 677 678 // The HTTP standard requires to use \r\n but for compatibility it recommends to accept also \n. 679 // We will add the current header to the CurlResponse.headers 680 if ((header != emptyLineCRLF) && (header != emptyLineLF)) { 681 m_response.headers.append(WTFMove(header)); 682 return receiveBytes; 683 } 684 685 // We can finish and send the ResourceResponse 686 long statusCode = 0; 687 if (auto code = m_curlHandle->getResponseCode()) 688 statusCode = *code; 689 690 long httpConnectCode = 0; 691 if (auto code = m_curlHandle->getHttpConnectCode()) 692 httpConnectCode = *code; 693 694 if ((100 <= statusCode) && (statusCode < 200)) { 695 // Just return when receiving http info, e.g. HTTP/1.1 100 Continue. 696 // If not, the request might be cancelled, because the MIME type will be empty for this response. 697 m_response = CurlResponse(); 698 return receiveBytes; 699 } 700 701 if (!statusCode && (httpConnectCode == 200)) { 702 // Comes here when receiving 200 Connection Established. Just return. 703 m_response = CurlResponse(); 704 return receiveBytes; 705 } 706 707 // If the FOLLOWLOCATION option is enabled for the curl handle then 708 // curl will follow the redirections internally. Thus this header callback 709 // will be called more than one time with the line starting "HTTP" for one job. 710 711 m_response.url = m_curlHandle->getEffectiveURL(); 712 m_response.statusCode = statusCode; 713 714 if (auto length = m_curlHandle->getContentLength()) 715 m_response.expectedContentLength = *length; 716 717 if (auto port = m_curlHandle->getPrimaryPort()) 718 m_response.connectPort = *port; 719 720 if (auto auth = m_curlHandle->getHttpAuthAvail()) 721 m_response.availableHttpAuth = *auth; 722 723 if (isMainThread()) 724 didReceiveAllHeaders(m_response); 725 else { 726 callOnMainThread([protectedThis = makeRef(*this), response = m_response.isolatedCopy()] { 727 if (!protectedThis->m_handle) 728 return; 729 protectedThis->didReceiveAllHeaders(response); 730 }); 731 } 732 733 return receiveBytes; 734 } 735 736 // called with data after all headers have been processed via headerCallback 737 size_t ResourceHandleCurlDelegate::didReceiveData(Ref<SharedBuffer>&& buffer) 738 { 739 if (!m_handle) 740 return 0; 741 742 if (m_defersLoading) 743 return 0; 744 745 size_t receiveBytes = buffer->size(); 746 747 // this shouldn't be necessary but apparently is. CURL writes the data 748 // of html page even if it is a redirect that was handled internally 749 // can be observed e.g. on gmail.com 750 if (auto httpCode = m_curlHandle->getResponseCode()) { 751 if (*httpCode >= 300 && *httpCode < 400) 752 return receiveBytes; 753 } 754 755 if (receiveBytes) { 756 if (isMainThread()) 757 didReceiveContentData(WTFMove(buffer)); 758 else { 759 callOnMainThread([protectedThis = makeRef(*this), buf = WTFMove(buffer)]() mutable { 760 if (!protectedThis->m_handle) 761 return; 762 protectedThis->didReceiveContentData(WTFMove(buf)); 763 }); 764 } 765 } 766 767 return receiveBytes; 768 } 769 770 /* This is called to obtain HTTP POST or PUT data. 771 Iterate through FormData elements and upload files. 772 Carefully respect the given buffer blockSize and fill the rest of the data at the next calls. 773 */ 774 size_t ResourceHandleCurlDelegate::willSendData(char* buffer, size_t blockSize, size_t numberOfBlocks) 775 { 776 ASSERT(!isMainThread()); 777 778 if (!m_handle) 779 return 0; 780 781 if (m_defersLoading) 782 return 0; 783 784 if (!blockSize || !numberOfBlocks) 785 return 0; 786 787 { 788 std::unique_lock<Lock> lock(m_workerThreadMutex); 789 790 m_sendBytes = 0; 791 792 if (isMainThread()) 793 prepareSendData(buffer, blockSize, numberOfBlocks); 794 else { 795 callOnMainThread([protectedThis = makeRef(*this), buffer, blockSize, numberOfBlocks] { 796 if (!protectedThis->m_handle) 797 return; 798 protectedThis->prepareSendData(buffer, blockSize, numberOfBlocks); 799 }); 800 801 m_workerThreadConditionVariable.wait(lock, [this] { 802 return m_sendBytes; 803 }); 804 } 805 } 806 807 return m_sendBytes; 808 } 809 810 CURLcode ResourceHandleCurlDelegate::willSetupSslCtxCallback(CURL*, void* sslCtx, void* userData) 811 { 812 return static_cast<ResourceHandleCurlDelegate*>(userData)->willSetupSslCtx(sslCtx); 813 } 814 815 size_t ResourceHandleCurlDelegate::didReceiveHeaderCallback(char* ptr, size_t blockSize, size_t numberOfBlocks, void* data) 816 { 817 return static_cast<ResourceHandleCurlDelegate*>(const_cast<void*>(data))->didReceiveHeader(String(static_cast<const char*>(ptr), blockSize * numberOfBlocks)); 818 } 819 820 size_t ResourceHandleCurlDelegate::didReceiveDataCallback(char* ptr, size_t blockSize, size_t numberOfBlocks, void* data) 821 { 822 return static_cast<ResourceHandleCurlDelegate*>(const_cast<void*>(data))->didReceiveData(SharedBuffer::create(ptr, blockSize * numberOfBlocks)); 823 } 824 825 size_t ResourceHandleCurlDelegate::willSendDataCallback(char* ptr, size_t blockSize, size_t numberOfBlocks, void* data) 826 { 827 return static_cast<ResourceHandleCurlDelegate*>(const_cast<void*>(data))->willSendData(ptr, blockSize, numberOfBlocks); 384 } 385 386 if (user.isEmpty() && password.isEmpty()) 387 return std::pair<String, String>("", ""); 388 389 return std::pair<String, String>(user, password); 828 390 } 829 391 -
trunk/Source/WebCore/platform/network/curl/ResourceHandleCurlDelegate.h
r222521 r222665 30 30 31 31 #include "Credential.h" 32 #include "CurlJobManager.h" 33 #include "CurlResponse.h" 34 #include "CurlSSLVerifier.h" 35 #include "FormDataStreamCurl.h" 32 #include "CurlRequestDelegate.h" 36 33 #include "ResourceRequest.h" 37 #include "ResourceResponse.h"38 #include <wtf/Condition.h>39 #include <wtf/ThreadSafeRefCounted.h>40 34 41 35 namespace WebCore { 42 36 37 class CurlRequest; 43 38 class MultipartHandle; 44 class ProtectionSpace;45 class ResourceError;46 39 class ResourceHandle; 47 class SharedBuffer;40 class ResourceResponse; 48 41 49 class ResourceHandleCurlDelegate final : public ThreadSafeRefCounted<ResourceHandleCurlDelegate>, public Curl JobClient{42 class ResourceHandleCurlDelegate final : public ThreadSafeRefCounted<ResourceHandleCurlDelegate>, public CurlRequestDelegate { 50 43 public: 51 44 ResourceHandleCurlDelegate(ResourceHandle*); … … 55 48 void releaseHandle(); 56 49 57 bool start() { start(false); return true; }50 bool start(); 58 51 void cancel(); 59 52 … … 64 57 65 58 private: 66 void retain() override;67 void release() override;68 69 CURL* handle() override { return m_curlHandle ? m_curlHandle->handle() : nullptr; }70 CURL* setupTransfer() override;71 void didCompleteTransfer(CURLcode) override;72 void didCancelTransfer() override;73 74 59 // Called from main thread. 75 60 ResourceResponse& response(); 76 61 77 void start(bool isSyncRequest);62 std::pair<String, String> getCredential(ResourceRequest&, bool); 78 63 79 void setupAuthentication();64 bool cancelledOrClientless(); 80 65 81 void didReceiveAllHeaders(const CurlResponse&); 82 void didReceiveContentData(Ref<SharedBuffer>&&); 83 void handleLocalReceiveResponse(); 84 void prepareSendData(char*, size_t blockSize, size_t numberOfBlocks); 85 86 void didFinish(NetworkLoadMetrics); 87 void didFail(const ResourceError&); 66 RefPtr<CurlRequest> createCurlRequest(ResourceRequest&); 67 void curlDidReceiveResponse(const CurlResponse&) override; 68 void curlDidReceiveBuffer(Ref<SharedBuffer>&&) override; 69 void curlDidComplete() override; 70 void curlDidFailWithError(const ResourceError&) override; 88 71 89 72 void handleDataURL(); 90 73 91 // Called from worker thread.92 void setupPOST();93 void setupPUT();94 size_t getFormElementsCount();95 void setupFormData(bool);96 void applyAuthentication();97 NetworkLoadMetrics getNetworkLoadMetrics();98 99 CURLcode willSetupSslCtx(void*);100 size_t didReceiveHeader(String&&);101 size_t didReceiveData(Ref<SharedBuffer>&&);102 size_t willSendData(char*, size_t blockSize, size_t numberOfBlocks);103 104 static CURLcode willSetupSslCtxCallback(CURL*, void*, void*);105 static size_t didReceiveHeaderCallback(char*, size_t blockSize, size_t numberOfBlocks, void*);106 static size_t didReceiveDataCallback(char*, size_t blockSize, size_t numberOfBlocks, void*);107 static size_t willSendDataCallback(char*, size_t blockSize, size_t numberOfBlocks, void*);108 109 74 // Used by main thread. 110 75 ResourceHandle* m_handle; 111 std::unique_ptr<FormDataStream> m_formDataStream;112 76 std::unique_ptr<MultipartHandle> m_multipartHandle; 113 unsigned shortm_authFailureCount { 0 };77 unsigned m_authFailureCount { 0 }; 114 78 // Used by worker thread. 115 79 ResourceRequest m_firstRequest; 116 HTTPHeaderMap m_customHTTPHeaderFields;80 ResourceRequest m_currentRequest; 117 81 bool m_shouldUseCredentialStorage; 118 82 String m_user; … … 121 85 bool m_defersLoading; 122 86 bool m_addedCacheValidationHeaders { false }; 123 Vector<char> m_postBytes; 124 std::unique_ptr<CurlHandle> m_curlHandle; 125 CurlSSLVerifier m_sslVerifier; 126 CurlResponse m_response; 127 bool m_didNotifyResponse { false }; 128 // Used by both threads. 129 bool m_isSyncRequest { false }; 130 Condition m_workerThreadConditionVariable; 131 Lock m_workerThreadMutex; 132 size_t m_sendBytes { 0 }; 87 RefPtr<CurlRequest> m_curlRequest; 133 88 }; 134 89
Note: See TracChangeset
for help on using the changeset viewer.