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