Changeset 230251 in webkit
- Timestamp:
- Apr 3, 2018 11:55:15 PM (6 years ago)
- Location:
- trunk/Source/WebCore
- Files:
-
- 4 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/Source/WebCore/ChangeLog
r230229 r230251 1 2018-04-03 Alex Christensen <achristensen@webkit.org> 2 3 Remove unused libsoup ResourceHandle implementation 4 https://bugs.webkit.org/show_bug.cgi?id=184048 5 6 Reviewed by Michael Catanzaro. 7 8 This code is unused since r228901 so let's remove it! 9 10 * platform/network/ResourceHandle.h: 11 * platform/network/ResourceHandleInternal.h: 12 (WebCore::ResourceHandleInternal::ResourceHandleInternal): 13 * platform/network/soup/ResourceHandleSoup.cpp: 14 (WebCore::ResourceHandle::~ResourceHandle): 15 (WebCore::ResourceHandleInternal::soupSession): 16 (WebCore::ResourceHandle::cancelledOrClientless): 17 (WebCore::ResourceHandle::ensureReadBuffer): 18 (WebCore::ResourceHandle::currentStreamPosition const): 19 (WebCore::ResourceHandle::platformContinueSynchronousDidReceiveResponse): 20 (WebCore::ResourceHandle::didStartRequest): 21 (WebCore::ResourceHandle::start): 22 (WebCore::ResourceHandle::releaseForDownload): 23 (WebCore::ResourceHandle::sendPendingRequest): 24 (WebCore::ResourceHandle::cancel): 25 (WebCore::ResourceHandle::shouldUseCredentialStorage): 26 (WebCore::ResourceHandle::continueDidReceiveAuthenticationChallenge): 27 (WebCore::ResourceHandle::didReceiveAuthenticationChallenge): 28 (WebCore::ResourceHandle::receivedRequestToContinueWithoutCredential): 29 (WebCore::ResourceHandle::receivedCredential): 30 (WebCore::ResourceHandle::receivedCancellation): 31 (WebCore::ResourceHandle::receivedChallengeRejection): 32 (WebCore::ResourceHandle::platformSetDefersLoading): 33 (WebCore::sessionFromContext): Deleted. 34 (WebCore::ResourceHandle::create): Deleted. 35 (WebCore::ResourceHandle::ResourceHandle): Deleted. 36 (WebCore::isAuthenticationFailureStatusCode): Deleted. 37 (WebCore::tlsErrorsChangedCallback): Deleted. 38 (WebCore::gotHeadersCallback): Deleted. 39 (WebCore::applyAuthenticationToRequest): Deleted. 40 (WebCore::restartedCallback): Deleted. 41 (WebCore::shouldRedirect): Deleted. 42 (WebCore::shouldRedirectAsGET): Deleted. 43 (WebCore::continueAfterWillSendRequest): Deleted. 44 (WebCore::doRedirect): Deleted. 45 (WebCore::redirectSkipCallback): Deleted. 46 (WebCore::wroteBodyDataCallback): Deleted. 47 (WebCore::cleanupSoupRequestOperation): Deleted. 48 (WebCore::nextMultipartResponsePartCallback): Deleted. 49 (WebCore::sendRequestCallback): Deleted. 50 (WebCore::continueAfterDidReceiveResponse): Deleted. 51 (WebCore::startingCallback): Deleted. 52 (WebCore::networkEventCallback): Deleted. 53 (WebCore::createSoupMessageForHandleAndRequest): Deleted. 54 (WebCore::createSoupRequestAndMessageForHandle): Deleted. 55 (WebCore::ResourceHandle::timeoutFired): Deleted. 56 (WebCore::waitingToSendRequest): Deleted. 57 (WebCore::readCallback): Deleted. 58 1 59 2018-04-03 Ross Kirsling <ross.kirsling@sony.com> 2 60 -
trunk/Source/WebCore/platform/network/ResourceHandle.h
r230019 r230251 41 41 #endif 42 42 43 #if USE(SOUP)44 typedef struct _GTlsCertificate GTlsCertificate;45 typedef struct _SoupSession SoupSession;46 typedef struct _SoupRequest SoupRequest;47 #endif48 49 43 #if USE(CF) 50 44 typedef const struct __CFData * CFDataRef; … … 93 87 class ResourceRequest; 94 88 class ResourceResponse; 95 class SoupNetworkSession;96 89 class SharedBuffer; 97 90 class Timer; … … 106 99 WEBCORE_EXPORT static RefPtr<ResourceHandle> create(NetworkingContext*, const ResourceRequest&, ResourceHandleClient*, bool defersLoading, bool shouldContentSniff, bool shouldContentEncodingSniff); 107 100 WEBCORE_EXPORT static void loadResourceSynchronously(NetworkingContext*, const ResourceRequest&, StoredCredentialsPolicy, ResourceError&, ResourceResponse&, Vector<char>& data); 108 109 #if USE(SOUP)110 static RefPtr<ResourceHandle> create(SoupNetworkSession&, const ResourceRequest&, ResourceHandleClient*, bool defersLoading, bool shouldContentSniff, bool shouldContentEncodingSniff);111 #endif112 113 101 WEBCORE_EXPORT virtual ~ResourceHandle(); 114 102 … … 180 168 WEBCORE_EXPORT static void forceContentSniffing(); 181 169 182 #if USE(CURL) || USE(SOUP)170 #if USE(CURL) 183 171 ResourceHandleInternal* getInternal() { return d.get(); } 184 #endif185 186 #if USE(SOUP)187 RefPtr<ResourceHandle> releaseForDownload(ResourceHandleClient*);188 void continueDidReceiveAuthenticationChallenge(const Credential& credentialFromPersistentStorage);189 void sendPendingRequest();190 bool cancelledOrClientless();191 void ensureReadBuffer();192 size_t currentStreamPosition() const;193 void didStartRequest();194 MonotonicTime m_requestTime;195 172 #endif 196 173 … … 244 221 }; 245 222 246 #if USE(SOUP)247 ResourceHandle(SoupNetworkSession&, const ResourceRequest&, ResourceHandleClient*, bool defersLoading, bool shouldContentSniff, bool shouldContentEncodingSniff);248 #endif249 250 223 void platformSetDefersLoading(bool); 251 224 … … 278 251 #if PLATFORM(COCOA) 279 252 void applySniffingPoliciesAndStoragePartitionIfNeeded(NSURLRequest*&, bool shouldContentSniff, bool shouldContentEncodingSniff); 280 #endif281 282 #if USE(SOUP)283 void timeoutFired();284 253 #endif 285 254 -
trunk/Source/WebCore/platform/network/ResourceHandleInternal.h
r230019 r230251 42 42 #endif 43 43 44 #if USE(SOUP)45 #include "GUniquePtrSoup.h"46 #include "SoupNetworkSession.h"47 #include <libsoup/soup.h>48 #include <wtf/RunLoop.h>49 #include <wtf/glib/GRefPtr.h>50 #endif51 52 44 #if PLATFORM(COCOA) 53 45 OBJC_CLASS NSURLAuthenticationChallenge; … … 79 71 #if USE(CFURLCONNECTION) 80 72 , m_currentRequest(request) 81 #endif82 #if USE(SOUP)83 , m_timeoutSource(RunLoop::main(), loader, &ResourceHandle::timeoutFired)84 73 #endif 85 74 , m_failureTimer(*loader, &ResourceHandle::failureTimerFired) … … 137 126 #endif 138 127 139 #if USE(SOUP)140 SoupNetworkSession* m_session { nullptr };141 GRefPtr<SoupMessage> m_soupMessage;142 ResourceResponse m_response;143 bool m_cancelled { false };144 GRefPtr<SoupRequest> m_soupRequest;145 GRefPtr<GInputStream> m_inputStream;146 GRefPtr<SoupMultipartInputStream> m_multipartInputStream;147 GRefPtr<GCancellable> m_cancellable;148 GRefPtr<GAsyncResult> m_deferredResult;149 RunLoop::Timer<ResourceHandle> m_timeoutSource;150 GUniquePtr<SoupBuffer> m_soupBuffer;151 unsigned long m_bodySize { 0 };152 unsigned long m_bodyDataSent { 0 };153 SoupSession* soupSession();154 int m_redirectCount { 0 };155 size_t m_previousPosition { 0 };156 bool m_useAuthenticationManager { true };157 struct {158 Credential credential;159 ProtectionSpace protectionSpace;160 } m_credentialDataToSaveInPersistentStore;161 #endif162 163 128 #if PLATFORM(COCOA) 164 129 // We need to keep a reference to the original challenge to be able to cancel it. -
trunk/Source/WebCore/platform/network/soup/ResourceHandleSoup.cpp
r230196 r230251 64 64 namespace WebCore { 65 65 66 static const size_t gDefaultReadBufferSize = 8192;67 68 static bool createSoupRequestAndMessageForHandle(ResourceHandle*, const ResourceRequest&);69 static void cleanupSoupRequestOperation(ResourceHandle*, bool isDestroying = false);70 static void sendRequestCallback(GObject*, GAsyncResult*, gpointer);71 static void readCallback(GObject*, GAsyncResult*, gpointer);72 static void continueAfterDidReceiveResponse(ResourceHandle*);73 74 66 ResourceHandleInternal::~ResourceHandleInternal() = default; 75 76 static SoupSession* sessionFromContext(NetworkingContext* context)77 {78 if (!context || !context->isValid())79 return NetworkStorageSession::defaultStorageSession().getOrCreateSoupNetworkSession().soupSession();80 return context->storageSession().getOrCreateSoupNetworkSession().soupSession();81 }82 67 83 68 ResourceHandle::~ResourceHandle() 84 69 { 85 cleanupSoupRequestOperation(this, true); 86 } 87 88 SoupSession* ResourceHandleInternal::soupSession() 89 { 90 return m_session ? m_session->soupSession() : sessionFromContext(m_context.get()); 91 } 92 93 RefPtr<ResourceHandle> ResourceHandle::create(SoupNetworkSession& session, const ResourceRequest& request, ResourceHandleClient* client, bool defersLoading, bool shouldContentSniff, bool shouldContentEncodingSniff) 94 { 95 auto newHandle = adoptRef(*new ResourceHandle(session, request, client, defersLoading, shouldContentSniff, shouldContentEncodingSniff)); 96 97 if (newHandle->d->m_scheduledFailureType != NoFailure) 98 return WTFMove(newHandle); 99 100 if (newHandle->start()) 101 return WTFMove(newHandle); 102 103 return nullptr; 104 } 105 106 ResourceHandle::ResourceHandle(SoupNetworkSession& session, const ResourceRequest& request, ResourceHandleClient* client, bool defersLoading, bool shouldContentSniff, bool shouldContentEncodingSniff) 107 : d(std::make_unique<ResourceHandleInternal>(this, nullptr, request, client, defersLoading, shouldContentSniff && shouldContentSniffURL(request.url()), shouldContentEncodingSniff)) 108 { 109 if (!request.url().isValid()) { 110 scheduleFailure(InvalidURLFailure); 111 return; 112 } 113 114 if (!portAllowed(request.url())) { 115 scheduleFailure(BlockedFailure); 116 return; 117 } 118 119 d->m_session = &session; 120 } 121 122 bool ResourceHandle::cancelledOrClientless() 123 { 124 if (!client()) 125 return true; 126 127 return getInternal()->m_cancelled; 128 } 129 130 void ResourceHandle::ensureReadBuffer() 131 { 132 ResourceHandleInternal* d = getInternal(); 133 134 if (d->m_soupBuffer) 135 return; 136 137 138 auto* buffer = static_cast<uint8_t*>(fastMalloc(gDefaultReadBufferSize)); 139 d->m_soupBuffer.reset(soup_buffer_new_with_owner(buffer, gDefaultReadBufferSize, buffer, fastFree)); 140 141 ASSERT(d->m_soupBuffer); 142 } 143 144 static bool isAuthenticationFailureStatusCode(int httpStatusCode) 145 { 146 return httpStatusCode == SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED || httpStatusCode == SOUP_STATUS_UNAUTHORIZED; 147 } 148 149 static void tlsErrorsChangedCallback(SoupMessage* message, GParamSpec*, gpointer data) 150 { 151 RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(data); 152 if (!handle || handle->cancelledOrClientless()) 153 return; 154 155 SoupNetworkSession::checkTLSErrors(handle->getInternal()->m_soupRequest.get(), message, [handle] (const ResourceError& error) { 156 if (error.isNull()) 157 return; 158 159 handle->client()->didFail(handle.get(), error); 160 handle->cancel(); 161 }); 162 } 163 164 static void gotHeadersCallback(SoupMessage* message, gpointer data) 165 { 166 ResourceHandle* handle = static_cast<ResourceHandle*>(data); 167 if (!handle || handle->cancelledOrClientless()) 168 return; 169 170 ResourceHandleInternal* d = handle->getInternal(); 171 172 if (d->m_context && d->m_context->isValid()) { 173 // We are a bit more conservative with the persistent credential storage than the session store, 174 // since we are waiting until we know that this authentication succeeded before actually storing. 175 // This is because we want to avoid hitting the disk twice (once to add and once to remove) for 176 // incorrect credentials or polluting the keychain with invalid credentials. 177 if (!isAuthenticationFailureStatusCode(message->status_code) && message->status_code < 500) { 178 d->m_context->storageSession().saveCredentialToPersistentStorage( 179 d->m_credentialDataToSaveInPersistentStore.protectionSpace, 180 d->m_credentialDataToSaveInPersistentStore.credential); 181 } 182 } 183 184 // The original response will be needed later to feed to willSendRequest in 185 // doRedirect() in case we are redirected. For this reason, we store it here. 186 d->m_response.updateFromSoupMessage(message); 187 } 188 189 static void applyAuthenticationToRequest(ResourceHandle* handle, ResourceRequest& request, bool redirect) 190 { 191 // m_user/m_pass are credentials given manually, for instance, by the arguments passed to XMLHttpRequest.open(). 192 ResourceHandleInternal* d = handle->getInternal(); 193 194 String partition = request.cachePartition(); 195 196 if (handle->shouldUseCredentialStorage()) { 197 if (d->m_user.isEmpty() && d->m_pass.isEmpty()) 198 d->m_initialCredential = CredentialStorage::defaultCredentialStorage().get(partition, request.url()); 199 else if (!redirect) { 200 // If there is already a protection space known for the URL, update stored credentials 201 // before sending a request. This makes it possible to implement logout by sending an 202 // XMLHttpRequest with known incorrect credentials, and aborting it immediately (so that 203 // an authentication dialog doesn't pop up). 204 CredentialStorage::defaultCredentialStorage().set(partition, Credential(d->m_user, d->m_pass, CredentialPersistenceNone), request.url()); 205 } 206 } 207 208 String user = d->m_user; 209 String password = d->m_pass; 210 if (!d->m_initialCredential.isEmpty()) { 211 user = d->m_initialCredential.user(); 212 password = d->m_initialCredential.password(); 213 } 214 215 if (user.isEmpty() && password.isEmpty()) { 216 // In case credential is not available from the handle and credential storage should not to be used, 217 // disable authentication manager so that credentials stored in libsoup are not used. 218 d->m_useAuthenticationManager = handle->shouldUseCredentialStorage(); 219 return; 220 } 221 222 // We always put the credentials into the URL. In the CFNetwork-port HTTP family credentials are applied in 223 // the didReceiveAuthenticationChallenge callback, but libsoup requires us to use this method to override 224 // any previously remembered credentials. It has its own per-session credential storage. 225 URL urlWithCredentials(request.url()); 226 urlWithCredentials.setUser(user); 227 urlWithCredentials.setPass(password); 228 request.setURL(urlWithCredentials); 229 } 230 231 // Called each time the message is going to be sent again except the first time. 232 // This happens when libsoup handles HTTP authentication. 233 static void restartedCallback(SoupMessage*, gpointer data) 234 { 235 ResourceHandle* handle = static_cast<ResourceHandle*>(data); 236 if (!handle || handle->cancelledOrClientless()) 237 return; 238 239 handle->m_requestTime = MonotonicTime::now(); 240 } 241 242 static bool shouldRedirect(ResourceHandle* handle) 243 { 244 ResourceHandleInternal* d = handle->getInternal(); 245 SoupMessage* message = d->m_soupMessage.get(); 246 247 // Some 3xx status codes aren't actually redirects. 248 if (message->status_code == 300 || message->status_code == 304 || message->status_code == 305 || message->status_code == 306) 249 return false; 250 251 if (!soup_message_headers_get_one(message->response_headers, "Location")) 252 return false; 253 254 return true; 255 } 256 257 static bool shouldRedirectAsGET(SoupMessage* message, URL& newURL, bool crossOrigin) 258 { 259 if (message->method == SOUP_METHOD_GET || message->method == SOUP_METHOD_HEAD) 260 return false; 261 262 if (!newURL.protocolIsInHTTPFamily()) 263 return true; 264 265 switch (message->status_code) { 266 case SOUP_STATUS_SEE_OTHER: 267 return true; 268 case SOUP_STATUS_FOUND: 269 case SOUP_STATUS_MOVED_PERMANENTLY: 270 if (message->method == SOUP_METHOD_POST) 271 return true; 272 break; 273 } 274 275 if (crossOrigin && message->method == SOUP_METHOD_DELETE) 276 return true; 277 278 return false; 279 } 280 281 static void continueAfterWillSendRequest(ResourceHandle* handle, ResourceRequest&& request) 282 { 283 // willSendRequest might cancel the load. 284 if (handle->cancelledOrClientless()) 285 return; 286 287 ResourceHandleInternal* d = handle->getInternal(); 288 if (protocolHostAndPortAreEqual(request.url(), d->m_response.url())) 289 applyAuthenticationToRequest(handle, request, true); 290 291 if (!createSoupRequestAndMessageForHandle(handle, request)) { 292 d->client()->cannotShowURL(handle); 293 return; 294 } 295 296 handle->sendPendingRequest(); 297 } 298 299 static void doRedirect(ResourceHandle* handle) 300 { 301 ResourceHandleInternal* d = handle->getInternal(); 302 static const int maxRedirects = 20; 303 304 if (d->m_redirectCount++ > maxRedirects) { 305 d->client()->didFail(handle, ResourceError::transportError(d->m_soupRequest.get(), SOUP_STATUS_TOO_MANY_REDIRECTS, "Too many redirects")); 306 cleanupSoupRequestOperation(handle); 307 return; 308 } 309 310 ResourceRequest newRequest = handle->firstRequest(); 311 SoupMessage* message = d->m_soupMessage.get(); 312 const char* location = soup_message_headers_get_one(message->response_headers, "Location"); 313 URL newURL = URL(URL(soup_message_get_uri(message)), location); 314 bool crossOrigin = !protocolHostAndPortAreEqual(handle->firstRequest().url(), newURL); 315 newRequest.setURL(newURL); 316 317 if (newRequest.httpMethod() != "GET") { 318 // Change newRequest method to GET if change was made during a previous redirection 319 // or if current redirection says so 320 if (message->method == SOUP_METHOD_GET || shouldRedirectAsGET(message, newURL, crossOrigin)) { 321 newRequest.setHTTPMethod("GET"); 322 newRequest.setHTTPBody(nullptr); 323 newRequest.clearHTTPContentType(); 324 } 325 } 326 327 // Should not set Referer after a redirect from a secure resource to non-secure one. 328 if (!newURL.protocolIs("https") && protocolIs(newRequest.httpReferrer(), "https") && handle->context()->shouldClearReferrerOnHTTPSToHTTPRedirect()) 329 newRequest.clearHTTPReferrer(); 330 331 d->m_user = newURL.user(); 332 d->m_pass = newURL.pass(); 333 newRequest.removeCredentials(); 334 335 if (crossOrigin) { 336 // If the network layer carries over authentication headers from the original request 337 // in a cross-origin redirect, we want to clear those headers here. 338 newRequest.clearHTTPAuthorization(); 339 newRequest.clearHTTPOrigin(); 340 341 // TODO: We are losing any username and password specified in the redirect URL, as this is the 342 // same behavior as the CFNet port. We should investigate if this is really what we want. 343 } 344 345 cleanupSoupRequestOperation(handle); 346 347 ResourceResponse responseCopy = d->m_response; 348 d->client()->willSendRequestAsync(handle, WTFMove(newRequest), WTFMove(responseCopy), [handle = makeRef(*handle)] (ResourceRequest&& request) { 349 continueAfterWillSendRequest(handle.ptr(), WTFMove(request)); 350 }); 351 } 352 353 static void redirectSkipCallback(GObject*, GAsyncResult* asyncResult, gpointer data) 354 { 355 RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(data); 356 357 if (handle->cancelledOrClientless()) { 358 cleanupSoupRequestOperation(handle.get()); 359 return; 360 } 361 362 GUniqueOutPtr<GError> error; 363 ResourceHandleInternal* d = handle->getInternal(); 364 gssize bytesSkipped = g_input_stream_skip_finish(d->m_inputStream.get(), asyncResult, &error.outPtr()); 365 if (error) { 366 handle->client()->didFail(handle.get(), ResourceError::genericGError(error.get(), d->m_soupRequest.get())); 367 cleanupSoupRequestOperation(handle.get()); 368 return; 369 } 370 371 if (bytesSkipped > 0) { 372 g_input_stream_skip_async(d->m_inputStream.get(), gDefaultReadBufferSize, RunLoopSourcePriority::AsyncIONetwork, 373 d->m_cancellable.get(), redirectSkipCallback, handle.get()); 374 return; 375 } 376 377 g_input_stream_close(d->m_inputStream.get(), 0, 0); 378 doRedirect(handle.get()); 379 } 380 381 static void wroteBodyDataCallback(SoupMessage*, SoupBuffer* buffer, gpointer data) 382 { 383 RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(data); 384 if (!handle) 385 return; 386 387 ASSERT(buffer); 388 ResourceHandleInternal* d = handle->getInternal(); 389 d->m_bodyDataSent += buffer->length; 390 391 if (handle->cancelledOrClientless()) 392 return; 393 394 handle->client()->didSendData(handle.get(), d->m_bodyDataSent, d->m_bodySize); 395 } 396 397 static void cleanupSoupRequestOperation(ResourceHandle* handle, bool isDestroying) 398 { 399 ResourceHandleInternal* d = handle->getInternal(); 400 401 d->m_soupRequest.clear(); 402 d->m_inputStream.clear(); 403 d->m_multipartInputStream.clear(); 404 d->m_cancellable.clear(); 405 d->m_soupBuffer.reset(); 406 407 if (d->m_soupMessage) { 408 g_signal_handlers_disconnect_matched(d->m_soupMessage.get(), G_SIGNAL_MATCH_DATA, 409 0, 0, 0, 0, handle); 410 g_object_set_data(G_OBJECT(d->m_soupMessage.get()), "handle", 0); 411 d->m_soupMessage.clear(); 412 } 413 414 d->m_timeoutSource.stop(); 415 416 if (!isDestroying) 417 handle->deref(); 418 } 419 420 size_t ResourceHandle::currentStreamPosition() const 421 { 422 GInputStream* baseStream = d->m_inputStream.get(); 423 while (!G_IS_SEEKABLE(baseStream) && G_IS_FILTER_INPUT_STREAM(baseStream)) 424 baseStream = g_filter_input_stream_get_base_stream(G_FILTER_INPUT_STREAM(baseStream)); 425 426 if (!G_IS_SEEKABLE(baseStream)) 427 return 0; 428 429 return g_seekable_tell(G_SEEKABLE(baseStream)); 430 } 431 432 static void nextMultipartResponsePartCallback(GObject* /*source*/, GAsyncResult* result, gpointer data) 433 { 434 RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(data); 435 436 if (handle->cancelledOrClientless()) { 437 cleanupSoupRequestOperation(handle.get()); 438 return; 439 } 440 441 ResourceHandleInternal* d = handle->getInternal(); 442 ASSERT(!d->m_inputStream); 443 444 GUniqueOutPtr<GError> error; 445 d->m_inputStream = adoptGRef(soup_multipart_input_stream_next_part_finish(d->m_multipartInputStream.get(), result, &error.outPtr())); 446 447 if (error) { 448 handle->client()->didFail(handle.get(), ResourceError::httpError(d->m_soupMessage.get(), error.get(), d->m_soupRequest.get())); 449 cleanupSoupRequestOperation(handle.get()); 450 return; 451 } 452 453 if (!d->m_inputStream) { 454 handle->client()->didFinishLoading(handle.get()); 455 cleanupSoupRequestOperation(handle.get()); 456 return; 457 } 458 459 d->m_response = ResourceResponse(); 460 d->m_response.setURL(handle->firstRequest().url()); 461 d->m_response.updateFromSoupMessageHeaders(soup_multipart_input_stream_get_headers(d->m_multipartInputStream.get())); 462 463 d->m_previousPosition = 0; 464 465 handle->didReceiveResponse(ResourceResponse(d->m_response), [handle = makeRef(*handle)] { 466 continueAfterDidReceiveResponse(handle.ptr()); 467 }); 468 } 469 470 static void sendRequestCallback(GObject*, GAsyncResult* result, gpointer data) 471 { 472 RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(data); 473 474 if (handle->cancelledOrClientless()) { 475 cleanupSoupRequestOperation(handle.get()); 476 return; 477 } 478 479 ResourceHandleInternal* d = handle->getInternal(); 480 SoupMessage* soupMessage = d->m_soupMessage.get(); 481 482 483 if (d->m_defersLoading) { 484 d->m_deferredResult = result; 485 return; 486 } 487 488 GUniqueOutPtr<GError> error; 489 GRefPtr<GInputStream> inputStream = adoptGRef(soup_request_send_finish(d->m_soupRequest.get(), result, &error.outPtr())); 490 if (error) { 491 handle->client()->didFail(handle.get(), ResourceError::httpError(soupMessage, error.get(), d->m_soupRequest.get())); 492 cleanupSoupRequestOperation(handle.get()); 493 return; 494 } 495 496 if (soupMessage) { 497 if (handle->shouldContentSniff() && soupMessage->status_code != SOUP_STATUS_NOT_MODIFIED) { 498 const char* sniffedType = soup_request_get_content_type(d->m_soupRequest.get()); 499 d->m_response.setSniffedContentType(sniffedType); 500 } 501 d->m_response.updateFromSoupMessage(soupMessage); 502 503 if (SOUP_STATUS_IS_REDIRECTION(soupMessage->status_code) && shouldRedirect(handle.get())) { 504 d->m_inputStream = inputStream; 505 g_input_stream_skip_async(d->m_inputStream.get(), gDefaultReadBufferSize, RunLoopSourcePriority::AsyncIONetwork, 506 d->m_cancellable.get(), redirectSkipCallback, handle.get()); 507 return; 508 } 509 } else { 510 d->m_response.setURL(handle->firstRequest().url()); 511 const gchar* contentType = soup_request_get_content_type(d->m_soupRequest.get()); 512 d->m_response.setMimeType(extractMIMETypeFromMediaType(contentType)); 513 d->m_response.setTextEncodingName(extractCharsetFromMediaType(contentType)); 514 d->m_response.setExpectedContentLength(soup_request_get_content_length(d->m_soupRequest.get())); 515 } 516 517 d->m_response.deprecatedNetworkLoadMetrics().responseStart = MonotonicTime::now() - handle->m_requestTime; 518 519 if (soupMessage && d->m_response.isMultipart()) 520 d->m_multipartInputStream = adoptGRef(soup_multipart_input_stream_new(soupMessage, inputStream.get())); 521 else 522 d->m_inputStream = inputStream; 523 524 handle->didReceiveResponse(ResourceResponse(d->m_response), [handle = makeRef(*handle)] { 525 continueAfterDidReceiveResponse(handle.ptr()); 526 }); 70 ASSERT_NOT_REACHED(); 527 71 } 528 72 529 73 void ResourceHandle::platformContinueSynchronousDidReceiveResponse() 530 74 { 531 continueAfterDidReceiveResponse(this); 532 } 533 534 static void continueAfterDidReceiveResponse(ResourceHandle* handle) 535 { 536 if (handle->cancelledOrClientless()) { 537 cleanupSoupRequestOperation(handle); 538 return; 539 } 540 541 ResourceHandleInternal* d = handle->getInternal(); 542 if (d->m_soupMessage && d->m_multipartInputStream && !d->m_inputStream) { 543 soup_multipart_input_stream_next_part_async(d->m_multipartInputStream.get(), RunLoopSourcePriority::AsyncIONetwork, 544 d->m_cancellable.get(), nextMultipartResponsePartCallback, handle); 545 return; 546 } 547 548 ASSERT(d->m_inputStream); 549 handle->ensureReadBuffer(); 550 g_input_stream_read_async(d->m_inputStream.get(), const_cast<char*>(d->m_soupBuffer->data), d->m_soupBuffer->length, 551 RunLoopSourcePriority::AsyncIONetwork, d->m_cancellable.get(), readCallback, handle); 552 } 553 554 void ResourceHandle::didStartRequest() 555 { 556 getInternal()->m_response.deprecatedNetworkLoadMetrics().requestStart = MonotonicTime::now() - m_requestTime; 557 } 558 559 #if SOUP_CHECK_VERSION(2, 49, 91) 560 static void startingCallback(SoupMessage*, ResourceHandle* handle) 561 { 562 handle->didStartRequest(); 563 } 564 #endif // SOUP_CHECK_VERSION(2, 49, 91) 565 566 static void networkEventCallback(SoupMessage*, GSocketClientEvent event, GIOStream*, gpointer data) 567 { 568 ResourceHandle* handle = static_cast<ResourceHandle*>(data); 569 if (!handle) 570 return; 571 572 if (handle->cancelledOrClientless()) 573 return; 574 575 ResourceHandleInternal* d = handle->getInternal(); 576 Seconds deltaTime = MonotonicTime::now() - handle->m_requestTime; 577 switch (event) { 578 case G_SOCKET_CLIENT_RESOLVING: 579 d->m_response.deprecatedNetworkLoadMetrics().domainLookupStart = deltaTime; 580 break; 581 case G_SOCKET_CLIENT_RESOLVED: 582 d->m_response.deprecatedNetworkLoadMetrics().domainLookupEnd = deltaTime; 583 break; 584 case G_SOCKET_CLIENT_CONNECTING: 585 d->m_response.deprecatedNetworkLoadMetrics().connectStart = deltaTime; 586 if (d->m_response.deprecatedNetworkLoadMetrics().domainLookupStart != Seconds(-1)) { 587 // WebCore/inspector/front-end/RequestTimingView.js assumes 588 // that DNS time is included in connection time so must 589 // substract here the DNS delta that will be added later (see 590 // WebInspector.RequestTimingView.createTimingTable in the 591 // file above for more details). 592 d->m_response.deprecatedNetworkLoadMetrics().connectStart -= 593 d->m_response.deprecatedNetworkLoadMetrics().domainLookupEnd - d->m_response.deprecatedNetworkLoadMetrics().domainLookupStart; 594 } 595 break; 596 case G_SOCKET_CLIENT_CONNECTED: 597 // Web Timing considers that connection time involves dns, proxy & TLS negotiation... 598 // so we better pick G_SOCKET_CLIENT_COMPLETE for connectEnd 599 break; 600 case G_SOCKET_CLIENT_PROXY_NEGOTIATING: 601 break; 602 case G_SOCKET_CLIENT_PROXY_NEGOTIATED: 603 break; 604 case G_SOCKET_CLIENT_TLS_HANDSHAKING: 605 d->m_response.deprecatedNetworkLoadMetrics().secureConnectionStart = deltaTime; 606 break; 607 case G_SOCKET_CLIENT_TLS_HANDSHAKED: 608 break; 609 case G_SOCKET_CLIENT_COMPLETE: 610 d->m_response.deprecatedNetworkLoadMetrics().connectEnd = deltaTime; 611 break; 612 default: 613 ASSERT_NOT_REACHED(); 614 break; 615 } 616 } 617 618 static bool createSoupMessageForHandleAndRequest(ResourceHandle* handle, const ResourceRequest& request) 619 { 620 ASSERT(handle); 621 622 ResourceHandleInternal* d = handle->getInternal(); 623 ASSERT(d->m_soupRequest); 624 625 d->m_soupMessage = adoptGRef(soup_request_http_get_message(SOUP_REQUEST_HTTP(d->m_soupRequest.get()))); 626 if (!d->m_soupMessage) 627 return false; 628 629 SoupMessage* soupMessage = d->m_soupMessage.get(); 630 request.updateSoupMessage(soupMessage); 631 d->m_bodySize = soupMessage->request_body->length; 632 633 g_object_set_data(G_OBJECT(soupMessage), "handle", handle); 634 if (!handle->shouldContentSniff()) 635 soup_message_disable_feature(soupMessage, SOUP_TYPE_CONTENT_SNIFFER); 636 if (!d->m_useAuthenticationManager) 637 soup_message_disable_feature(soupMessage, SOUP_TYPE_AUTH_MANAGER); 638 639 // Make sure we have an Accept header for subresources; some sites 640 // want this to serve some of their subresources 641 if (!soup_message_headers_get_one(soupMessage->request_headers, "Accept")) 642 soup_message_headers_append(soupMessage->request_headers, "Accept", "*/*"); 643 644 // In the case of XHR .send() and .send("") explicitly tell libsoup to send a zero content-lenght header 645 // for consistency with other backends (e.g. Chromium's) and other UA implementations like FF. It's done 646 // in the backend here instead of in XHR code since in XHR CORS checking prevents us from this kind of 647 // late header manipulation. 648 if ((request.httpMethod() == "POST" || request.httpMethod() == "PUT") && !d->m_bodySize) 649 soup_message_headers_set_content_length(soupMessage->request_headers, 0); 650 651 g_signal_connect(d->m_soupMessage.get(), "notify::tls-errors", G_CALLBACK(tlsErrorsChangedCallback), handle); 652 g_signal_connect(d->m_soupMessage.get(), "got-headers", G_CALLBACK(gotHeadersCallback), handle); 653 g_signal_connect(d->m_soupMessage.get(), "wrote-body-data", G_CALLBACK(wroteBodyDataCallback), handle); 654 655 unsigned flags = SOUP_MESSAGE_NO_REDIRECT; 656 soup_message_set_flags(d->m_soupMessage.get(), static_cast<SoupMessageFlags>(soup_message_get_flags(d->m_soupMessage.get()) | flags)); 657 658 #if SOUP_CHECK_VERSION(2, 49, 91) 659 g_signal_connect(d->m_soupMessage.get(), "starting", G_CALLBACK(startingCallback), handle); 660 #endif 661 g_signal_connect(d->m_soupMessage.get(), "network-event", G_CALLBACK(networkEventCallback), handle); 662 g_signal_connect(d->m_soupMessage.get(), "restarted", G_CALLBACK(restartedCallback), handle); 663 664 #if SOUP_CHECK_VERSION(2, 43, 1) 665 soup_message_set_priority(d->m_soupMessage.get(), toSoupMessagePriority(request.priority())); 666 #endif 667 668 return true; 669 } 670 671 static bool createSoupRequestAndMessageForHandle(ResourceHandle* handle, const ResourceRequest& request) 672 { 673 ResourceHandleInternal* d = handle->getInternal(); 674 675 GUniquePtr<SoupURI> soupURI = request.createSoupURI(); 676 if (!soupURI) 677 return false; 678 679 GUniqueOutPtr<GError> error; 680 d->m_soupRequest = adoptGRef(soup_session_request_uri(d->soupSession(), soupURI.get(), &error.outPtr())); 681 if (error) { 682 d->m_soupRequest.clear(); 683 return false; 684 } 685 686 // SoupMessages are only applicable to HTTP-family requests. 687 if (request.url().protocolIsInHTTPFamily() && !createSoupMessageForHandleAndRequest(handle, request)) { 688 d->m_soupRequest.clear(); 689 return false; 690 } 691 692 request.updateSoupRequest(d->m_soupRequest.get()); 693 694 return true; 75 ASSERT_NOT_REACHED(); 695 76 } 696 77 697 78 bool ResourceHandle::start() 698 79 { 699 ASSERT(!d->m_soupMessage); 700 701 // The frame could be null if the ResourceHandle is not associated to any 702 // Frame, e.g. if we are downloading a file. 703 // If the frame is not null but the page is null this must be an attempted 704 // load from an unload handler, so let's just block it. 705 // If both the frame and the page are not null the context is valid. 706 if (d->m_context && !d->m_context->isValid()) 707 return false; 708 709 // Only allow the POST and GET methods for non-HTTP requests. 710 const ResourceRequest& request = firstRequest(); 711 if (!request.url().protocolIsInHTTPFamily() && request.httpMethod() != "GET" && request.httpMethod() != "POST") { 712 this->scheduleFailure(InvalidURLFailure); // Error must not be reported immediately 713 return true; 714 } 715 716 applyAuthenticationToRequest(this, firstRequest(), false); 717 718 if (!createSoupRequestAndMessageForHandle(this, request)) { 719 this->scheduleFailure(InvalidURLFailure); // Error must not be reported immediately 720 return true; 721 } 722 723 // Send the request only if it's not been explicitly deferred. 724 if (!d->m_defersLoading) 725 sendPendingRequest(); 726 727 return true; 728 } 729 730 RefPtr<ResourceHandle> ResourceHandle::releaseForDownload(ResourceHandleClient* downloadClient) 731 { 732 // We don't adopt the ref, as it will be released by cleanupSoupRequestOperation, which should always run. 733 ResourceHandle* newHandle = new ResourceHandle(d->m_context.get(), firstRequest(), nullptr, d->m_defersLoading, d->m_shouldContentSniff, d->m_shouldContentEncodingSniff); 734 newHandle->relaxAdoptionRequirement(); 735 std::swap(d, newHandle->d); 736 737 g_signal_handlers_disconnect_matched(newHandle->d->m_soupMessage.get(), G_SIGNAL_MATCH_DATA, 0, 0, nullptr, nullptr, this); 738 g_object_set_data(G_OBJECT(newHandle->d->m_soupMessage.get()), "handle", newHandle); 739 740 newHandle->d->m_client = downloadClient; 741 continueAfterDidReceiveResponse(newHandle); 742 743 return newHandle; 744 } 745 746 void ResourceHandle::timeoutFired() 747 { 748 client()->didFail(this, ResourceError::timeoutError(firstRequest().url())); 749 cancel(); 750 } 751 752 void ResourceHandle::sendPendingRequest() 753 { 754 m_requestTime = MonotonicTime::now(); 755 756 if (d->m_firstRequest.timeoutInterval() > 0) 757 d->m_timeoutSource.startOneShot(1_s * d->m_firstRequest.timeoutInterval()); 758 759 // Balanced by a deref() in cleanupSoupRequestOperation, which should always run. 760 ref(); 761 762 d->m_cancellable = adoptGRef(g_cancellable_new()); 763 soup_request_send_async(d->m_soupRequest.get(), d->m_cancellable.get(), sendRequestCallback, this); 80 ASSERT_NOT_REACHED(); 81 return false; 764 82 } 765 83 766 84 void ResourceHandle::cancel() 767 85 { 768 d->m_cancelled = true; 769 if (d->m_soupMessage) 770 soup_session_cancel_message(d->soupSession(), d->m_soupMessage.get(), SOUP_STATUS_CANCELLED); 771 else if (d->m_cancellable) 772 g_cancellable_cancel(d->m_cancellable.get()); 86 ASSERT_NOT_REACHED(); 773 87 } 774 88 775 89 bool ResourceHandle::shouldUseCredentialStorage() 776 90 { 777 return (!client() || client()->shouldUseCredentialStorage(this)) && firstRequest().url().protocolIsInHTTPFamily(); 91 ASSERT_NOT_REACHED(); 92 return false; 778 93 } 779 94 780 void ResourceHandle:: continueDidReceiveAuthenticationChallenge(const Credential& credentialFromPersistentStorage)95 void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChallenge&) 781 96 { 782 ASSERT(!d->m_currentWebChallenge.isNull()); 783 AuthenticationChallenge& challenge = d->m_currentWebChallenge; 784 785 ASSERT(d->m_soupMessage); 786 if (!credentialFromPersistentStorage.isEmpty()) 787 challenge.setProposedCredential(credentialFromPersistentStorage); 788 789 if (!client()) { 790 soup_session_unpause_message(d->soupSession(), d->m_soupMessage.get()); 791 clearAuthentication(); 792 return; 793 } 794 795 client()->didReceiveAuthenticationChallenge(this, challenge); 97 ASSERT_NOT_REACHED(); 796 98 } 797 99 798 void ResourceHandle:: didReceiveAuthenticationChallenge(const AuthenticationChallenge& challenge)100 void ResourceHandle::receivedRequestToContinueWithoutCredential(const AuthenticationChallenge&) 799 101 { 800 ASSERT(d->m_currentWebChallenge.isNull()); 801 802 String partition = firstRequest().cachePartition(); 803 804 // FIXME: Per the specification, the user shouldn't be asked for credentials if there were incorrect ones provided explicitly. 805 bool useCredentialStorage = shouldUseCredentialStorage(); 806 if (useCredentialStorage) { 807 if (!d->m_initialCredential.isEmpty() || challenge.previousFailureCount()) { 808 // The stored credential wasn't accepted, stop using it. There is a race condition 809 // here, since a different credential might have already been stored by another 810 // ResourceHandle, but the observable effect should be very minor, if any. 811 CredentialStorage::defaultCredentialStorage().remove(partition, challenge.protectionSpace()); 812 } 813 814 if (!challenge.previousFailureCount()) { 815 Credential credential = CredentialStorage::defaultCredentialStorage().get(partition, challenge.protectionSpace()); 816 if (!credential.isEmpty() && credential != d->m_initialCredential) { 817 ASSERT(credential.persistence() == CredentialPersistenceNone); 818 819 // Store the credential back, possibly adding it as a default for this directory. 820 if (isAuthenticationFailureStatusCode(challenge.failureResponse().httpStatusCode())) 821 CredentialStorage::defaultCredentialStorage().set(partition, credential, challenge.protectionSpace(), challenge.failureResponse().url()); 822 823 soup_auth_authenticate(challenge.soupAuth(), credential.user().utf8().data(), credential.password().utf8().data()); 824 return; 825 } 826 } 827 } 828 829 d->m_currentWebChallenge = challenge; 830 soup_session_pause_message(d->soupSession(), d->m_soupMessage.get()); 831 832 // We could also do this before we even start the request, but that would be at the expense 833 // of all request latency, versus a one-time latency for the small subset of requests that 834 // use HTTP authentication. In the end, this doesn't matter much, because persistent credentials 835 // will become session credentials after the first use. 836 if (useCredentialStorage && d->m_context && d->m_context->isValid()) { 837 d->m_context->storageSession().getCredentialFromPersistentStorage(challenge.protectionSpace(), d->m_cancellable.get(), [this, protectedThis = makeRef(*this)] (Credential&& credential) { 838 continueDidReceiveAuthenticationChallenge(WTFMove(credential)); 839 }); 840 return; 841 } 842 843 continueDidReceiveAuthenticationChallenge(Credential()); 102 ASSERT_NOT_REACHED(); 844 103 } 845 104 846 void ResourceHandle::received RequestToContinueWithoutCredential(const AuthenticationChallenge& challenge)105 void ResourceHandle::receivedCredential(const AuthenticationChallenge&, const Credential&) 847 106 { 848 ASSERT(!challenge.isNull()); 849 if (challenge != d->m_currentWebChallenge) 850 return; 851 soup_session_unpause_message(d->soupSession(), d->m_soupMessage.get()); 852 853 clearAuthentication(); 107 ASSERT_NOT_REACHED(); 854 108 } 855 109 856 void ResourceHandle::receivedC redential(const AuthenticationChallenge& challenge, const Credential& credential)110 void ResourceHandle::receivedCancellation(const AuthenticationChallenge&) 857 111 { 858 ASSERT(!challenge.isNull()); 859 if (challenge != d->m_currentWebChallenge) 860 return; 861 862 // FIXME: Support empty credentials. Currently, an empty credential cannot be stored in WebCore credential storage, as that's empty value for its map. 863 if (credential.isEmpty()) { 864 receivedRequestToContinueWithoutCredential(challenge); 865 return; 866 } 867 868 String partition = firstRequest().cachePartition(); 869 870 if (shouldUseCredentialStorage()) { 871 // Eventually we will manage per-session credentials only internally or use some newly-exposed API from libsoup, 872 // because once we authenticate via libsoup, there is no way to ignore it for a particular request. Right now, 873 // we place the credentials in the store even though libsoup will never fire the authenticate signal again for 874 // this protection space. 875 if (credential.persistence() == CredentialPersistenceForSession || credential.persistence() == CredentialPersistencePermanent) 876 CredentialStorage::defaultCredentialStorage().set(partition, credential, challenge.protectionSpace(), challenge.failureResponse().url()); 877 878 if (credential.persistence() == CredentialPersistencePermanent) { 879 d->m_credentialDataToSaveInPersistentStore.credential = credential; 880 d->m_credentialDataToSaveInPersistentStore.protectionSpace = challenge.protectionSpace(); 881 } 882 } 883 884 ASSERT(d->m_soupMessage); 885 soup_auth_authenticate(challenge.soupAuth(), credential.user().utf8().data(), credential.password().utf8().data()); 886 soup_session_unpause_message(d->soupSession(), d->m_soupMessage.get()); 887 888 clearAuthentication(); 889 } 890 891 void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challenge) 892 { 893 ASSERT(!challenge.isNull()); 894 if (challenge != d->m_currentWebChallenge) 895 return; 896 897 if (cancelledOrClientless()) { 898 clearAuthentication(); 899 return; 900 } 901 902 ASSERT(d->m_soupMessage); 903 soup_session_unpause_message(d->soupSession(), d->m_soupMessage.get()); 904 905 if (client()) 906 client()->receivedCancellation(this, challenge); 907 908 clearAuthentication(); 112 ASSERT_NOT_REACHED(); 909 113 } 910 114 … … 914 118 } 915 119 916 void ResourceHandle::receivedChallengeRejection(const AuthenticationChallenge& challenge)120 void ResourceHandle::receivedChallengeRejection(const AuthenticationChallenge&) 917 121 { 918 // This is only used by layout tests, soup based ports don't implement this. 919 notImplemented(); 920 receivedRequestToContinueWithoutCredential(challenge); 122 ASSERT_NOT_REACHED(); 921 123 } 922 124 923 static bool waitingToSendRequest(ResourceHandle* handle)125 void ResourceHandle::platformSetDefersLoading(bool) 924 126 { 925 // We need to check for d->m_soupRequest because the request may have raised a failure 926 // (for example invalid URLs). We cannot simply check for d->m_scheduledFailure because 927 // it's cleared as soon as the failure event is fired. 928 return handle->getInternal()->m_soupRequest && !handle->getInternal()->m_cancellable; 929 } 930 931 void ResourceHandle::platformSetDefersLoading(bool defersLoading) 932 { 933 if (cancelledOrClientless()) 934 return; 935 936 // Except when canceling a possible timeout timer, we only need to take action here to UN-defer loading. 937 if (defersLoading) { 938 d->m_timeoutSource.stop(); 939 return; 940 } 941 942 if (waitingToSendRequest(this)) { 943 sendPendingRequest(); 944 return; 945 } 946 947 if (d->m_deferredResult) { 948 GRefPtr<GAsyncResult> asyncResult = adoptGRef(d->m_deferredResult.leakRef()); 949 950 if (d->m_inputStream) 951 readCallback(G_OBJECT(d->m_inputStream.get()), asyncResult.get(), this); 952 else 953 sendRequestCallback(G_OBJECT(d->m_soupRequest.get()), asyncResult.get(), this); 954 } 127 ASSERT_NOT_REACHED(); 955 128 } 956 129 … … 960 133 } 961 134 962 static void readCallback(GObject*, GAsyncResult* asyncResult, gpointer data)963 {964 RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(data);965 966 if (handle->cancelledOrClientless()) {967 cleanupSoupRequestOperation(handle.get());968 return;969 }970 971 ResourceHandleInternal* d = handle->getInternal();972 if (d->m_defersLoading) {973 d->m_deferredResult = asyncResult;974 return;975 }976 977 GUniqueOutPtr<GError> error;978 gssize bytesRead = g_input_stream_read_finish(d->m_inputStream.get(), asyncResult, &error.outPtr());979 980 if (error) {981 handle->client()->didFail(handle.get(), ResourceError::genericGError(error.get(), d->m_soupRequest.get()));982 cleanupSoupRequestOperation(handle.get());983 return;984 }985 986 if (!bytesRead) {987 // If this is a multipart message, we'll look for another part.988 if (d->m_soupMessage && d->m_multipartInputStream) {989 d->m_inputStream.clear();990 soup_multipart_input_stream_next_part_async(d->m_multipartInputStream.get(), RunLoopSourcePriority::AsyncIONetwork,991 d->m_cancellable.get(), nextMultipartResponsePartCallback, handle.get());992 return;993 }994 995 g_input_stream_close(d->m_inputStream.get(), 0, 0);996 997 handle->client()->didFinishLoading(handle.get());998 cleanupSoupRequestOperation(handle.get());999 return;1000 }1001 1002 // It's mandatory to have sent a response before sending data1003 ASSERT(!d->m_response.isNull());1004 1005 size_t currentPosition = handle->currentStreamPosition();1006 size_t encodedDataLength = currentPosition ? currentPosition - d->m_previousPosition : bytesRead;1007 1008 ASSERT(d->m_soupBuffer);1009 d->m_soupBuffer->length = bytesRead; // The buffer might be larger than the number of bytes read. SharedBuffer looks at the length property.1010 handle->client()->didReceiveBuffer(handle.get(), SharedBuffer::wrapSoupBuffer(d->m_soupBuffer.release()), encodedDataLength);1011 1012 d->m_previousPosition = currentPosition;1013 1014 // didReceiveBuffer may cancel the load, which may release the last reference.1015 if (handle->cancelledOrClientless()) {1016 cleanupSoupRequestOperation(handle.get());1017 return;1018 }1019 1020 handle->ensureReadBuffer();1021 g_input_stream_read_async(d->m_inputStream.get(), const_cast<char*>(d->m_soupBuffer->data), d->m_soupBuffer->length, RunLoopSourcePriority::AsyncIONetwork,1022 d->m_cancellable.get(), readCallback, handle.get());1023 }1024 1025 135 } 1026 136
Note: See TracChangeset
for help on using the changeset viewer.