7ef0963ee3cf62bf5879dae12783bbed73639502
[WebKit.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 "CookieJarSoup.h"
35 #include "CredentialStorage.h"
36 #include "FileSystem.h"
37 #include "GUniquePtrSoup.h"
38 #include "HTTPParsers.h"
39 #include "LocalizedStrings.h"
40 #include "MIMETypeRegistry.h"
41 #include "NetworkingContext.h"
42 #include "NotImplemented.h"
43 #include "ResourceError.h"
44 #include "ResourceHandleClient.h"
45 #include "ResourceHandleInternal.h"
46 #include "ResourceResponse.h"
47 #include "SharedBuffer.h"
48 #include "SoupNetworkSession.h"
49 #include "TextEncoding.h"
50 #include <errno.h>
51 #include <fcntl.h>
52 #include <gio/gio.h>
53 #include <glib.h>
54 #include <libsoup/soup.h>
55 #include <sys/stat.h>
56 #include <sys/types.h>
57 #if !COMPILER(MSVC)
58 #include <unistd.h>
59 #endif
60 #include <wtf/CurrentTime.h>
61 #include <wtf/SHA1.h>
62 #include <wtf/gobject/GRefPtr.h>
63 #include <wtf/text/Base64.h>
64 #include <wtf/text/CString.h>
65
66 #if ENABLE(BLOB)
67 #include "BlobData.h"
68 #include "BlobRegistryImpl.h"
69 #include "BlobStorageData.h"
70 #endif
71
72 #if PLATFORM(GTK)
73 #include "CredentialBackingStore.h"
74 #endif
75
76 namespace WebCore {
77
78 static bool loadingSynchronousRequest = false;
79 static const size_t gDefaultReadBufferSize = 8192;
80
81 class WebCoreSynchronousLoader : public ResourceHandleClient {
82     WTF_MAKE_NONCOPYABLE(WebCoreSynchronousLoader);
83 public:
84
85     WebCoreSynchronousLoader(ResourceError& error, ResourceResponse& response, SoupSession* session, Vector<char>& data, StoredCredentials storedCredentials)
86         : m_error(error)
87         , m_response(response)
88         , m_session(session)
89         , m_data(data)
90         , m_finished(false)
91         , m_storedCredentials(storedCredentials)
92         
93     {
94         // We don't want any timers to fire while we are doing our synchronous load
95         // so we replace the thread default main context. The main loop iterations
96         // will only process GSources associated with this inner context.
97         loadingSynchronousRequest = true;
98         GRefPtr<GMainContext> innerMainContext = adoptGRef(g_main_context_new());
99         g_main_context_push_thread_default(innerMainContext.get());
100         m_mainLoop = adoptGRef(g_main_loop_new(innerMainContext.get(), false));
101
102         adjustMaxConnections(1);
103     }
104
105     ~WebCoreSynchronousLoader()
106     {
107         adjustMaxConnections(-1);
108
109         GMainContext* context = g_main_context_get_thread_default();
110         while (g_main_context_pending(context))
111             g_main_context_iteration(context, FALSE);
112
113         g_main_context_pop_thread_default(context);
114         loadingSynchronousRequest = false;
115     }
116
117     void adjustMaxConnections(int adjustment)
118     {
119         int maxConnections, maxConnectionsPerHost;
120         g_object_get(m_session,
121                      SOUP_SESSION_MAX_CONNS, &maxConnections,
122                      SOUP_SESSION_MAX_CONNS_PER_HOST, &maxConnectionsPerHost,
123                      NULL);
124         maxConnections += adjustment;
125         maxConnectionsPerHost += adjustment;
126         g_object_set(m_session,
127                      SOUP_SESSION_MAX_CONNS, maxConnections,
128                      SOUP_SESSION_MAX_CONNS_PER_HOST, maxConnectionsPerHost,
129                      NULL);
130
131     }
132
133     virtual bool isSynchronousClient()
134     {
135         return true;
136     }
137
138     virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse& response)
139     {
140         m_response = response;
141     }
142
143     virtual void didReceiveData(ResourceHandle*, const char* /* data */, unsigned /* length */, int)
144     {
145         ASSERT_NOT_REACHED();
146     }
147
148     virtual void didReceiveBuffer(ResourceHandle*, PassRefPtr<SharedBuffer> buffer, int /* encodedLength */)
149     {
150         // This pattern is suggested by SharedBuffer.h.
151         const char* segment;
152         unsigned position = 0;
153         while (unsigned length = buffer->getSomeData(segment, position)) {
154             m_data.append(segment, length);
155             position += length;
156         }
157     }
158
159     virtual void didFinishLoading(ResourceHandle*, double)
160     {
161         if (g_main_loop_is_running(m_mainLoop.get()))
162             g_main_loop_quit(m_mainLoop.get());
163         m_finished = true;
164     }
165
166     virtual void didFail(ResourceHandle* handle, const ResourceError& error)
167     {
168         m_error = error;
169         didFinishLoading(handle, 0);
170     }
171
172     virtual void didReceiveAuthenticationChallenge(ResourceHandle*, const AuthenticationChallenge& challenge)
173     {
174         // We do not handle authentication for synchronous XMLHttpRequests.
175         challenge.authenticationClient()->receivedRequestToContinueWithoutCredential(challenge);
176     }
177
178     virtual bool shouldUseCredentialStorage(ResourceHandle*)
179     {
180         return m_storedCredentials == AllowStoredCredentials;
181     }
182
183     void run()
184     {
185         if (!m_finished)
186             g_main_loop_run(m_mainLoop.get());
187     }
188
189 private:
190     ResourceError& m_error;
191     ResourceResponse& m_response;
192     SoupSession* m_session;
193     Vector<char>& m_data;
194     bool m_finished;
195     GRefPtr<GMainLoop> m_mainLoop;
196     StoredCredentials m_storedCredentials;
197 };
198
199 class HostTLSCertificateSet {
200 public:
201     void add(GTlsCertificate* certificate)
202     {
203         String certificateHash = computeCertificateHash(certificate);
204         if (!certificateHash.isEmpty())
205             m_certificates.add(certificateHash);
206     }
207
208     bool contains(GTlsCertificate* certificate)
209     {
210         return m_certificates.contains(computeCertificateHash(certificate));
211     }
212
213 private:
214     static String computeCertificateHash(GTlsCertificate* certificate)
215     {
216         GRefPtr<GByteArray> certificateData;
217         g_object_get(G_OBJECT(certificate), "certificate", &certificateData.outPtr(), NULL);
218         if (!certificateData)
219             return String();
220
221         SHA1 sha1;
222         sha1.addBytes(certificateData->data, certificateData->len);
223
224         SHA1::Digest digest;
225         sha1.computeHash(digest);
226
227         return base64Encode(reinterpret_cast<const char*>(digest.data()), SHA1::hashSize);
228     }
229
230     HashSet<String> m_certificates;
231 };
232
233 static bool createSoupRequestAndMessageForHandle(ResourceHandle*, const ResourceRequest&, bool isHTTPFamilyRequest);
234 static void cleanupSoupRequestOperation(ResourceHandle*, bool isDestroying = false);
235 static void sendRequestCallback(GObject*, GAsyncResult*, gpointer);
236 static void readCallback(GObject*, GAsyncResult*, gpointer);
237 static gboolean requestTimeoutCallback(void*);
238 #if ENABLE(WEB_TIMING)
239 static int  milisecondsSinceRequest(double requestTime);
240 #endif
241 static void continueAfterDidReceiveResponse(ResourceHandle*);
242
243 static bool gIgnoreSSLErrors = false;
244
245 static HashSet<String>& allowsAnyHTTPSCertificateHosts()
246 {
247     DEPRECATED_DEFINE_STATIC_LOCAL(HashSet<String>, hosts, ());
248     return hosts;
249 }
250
251 typedef HashMap<String, HostTLSCertificateSet> CertificatesMap;
252 static CertificatesMap& clientCertificates()
253 {
254     DEPRECATED_DEFINE_STATIC_LOCAL(CertificatesMap, certificates, ());
255     return certificates;
256 }
257
258 ResourceHandleInternal::~ResourceHandleInternal()
259 {
260 }
261
262 static SoupSession* sessionFromContext(NetworkingContext* context)
263 {
264     if (!context || !context->isValid())
265         return SoupNetworkSession::defaultSession().soupSession();
266     return context->storageSession().soupNetworkSession().soupSession();
267 }
268
269 ResourceHandle::~ResourceHandle()
270 {
271     cleanupSoupRequestOperation(this, true);
272 }
273
274 SoupSession* ResourceHandleInternal::soupSession()
275 {
276     return sessionFromContext(m_context.get());
277 }
278
279 bool ResourceHandle::cancelledOrClientless()
280 {
281     if (!client())
282         return true;
283
284     return getInternal()->m_cancelled;
285 }
286
287 void ResourceHandle::ensureReadBuffer()
288 {
289     ResourceHandleInternal* d = getInternal();
290
291     if (d->m_soupBuffer)
292         return;
293
294     // Non-NetworkProcess clients are able to give a buffer to the ResourceHandle to avoid expensive copies. If
295     // we do get a buffer from the client, we want the client to free it, so we create the soup buffer with
296     // SOUP_MEMORY_TEMPORARY.
297     size_t bufferSize;
298     char* bufferFromClient = client()->getOrCreateReadBuffer(gDefaultReadBufferSize, bufferSize);
299     if (bufferFromClient)
300         d->m_soupBuffer.reset(soup_buffer_new(SOUP_MEMORY_TEMPORARY, bufferFromClient, bufferSize));
301     else
302         d->m_soupBuffer.reset(soup_buffer_new(SOUP_MEMORY_TAKE, static_cast<char*>(g_malloc(gDefaultReadBufferSize)), gDefaultReadBufferSize));
303
304     ASSERT(d->m_soupBuffer);
305 }
306
307 static bool isAuthenticationFailureStatusCode(int httpStatusCode)
308 {
309     return httpStatusCode == SOUP_STATUS_PROXY_AUTHENTICATION_REQUIRED || httpStatusCode == SOUP_STATUS_UNAUTHORIZED;
310 }
311
312 static void gotHeadersCallback(SoupMessage* message, gpointer data)
313 {
314     ResourceHandle* handle = static_cast<ResourceHandle*>(data);
315     if (!handle || handle->cancelledOrClientless())
316         return;
317
318     ResourceHandleInternal* d = handle->getInternal();
319
320 #if ENABLE(WEB_TIMING)
321     if (d->m_response.resourceLoadTiming())
322         d->m_response.resourceLoadTiming()->receiveHeadersEnd = milisecondsSinceRequest(d->m_response.resourceLoadTiming()->requestTime);
323 #endif
324
325 #if PLATFORM(GTK)
326     // We are a bit more conservative with the persistent credential storage than the session store,
327     // since we are waiting until we know that this authentication succeeded before actually storing.
328     // This is because we want to avoid hitting the disk twice (once to add and once to remove) for
329     // incorrect credentials or polluting the keychain with invalid credentials.
330     if (!isAuthenticationFailureStatusCode(message->status_code) && message->status_code < 500 && !d->m_credentialDataToSaveInPersistentStore.credential.isEmpty()) {
331         credentialBackingStore().storeCredentialsForChallenge(
332             d->m_credentialDataToSaveInPersistentStore.challenge,
333             d->m_credentialDataToSaveInPersistentStore.credential);
334     }
335 #endif
336
337     // The original response will be needed later to feed to willSendRequest in
338     // doRedirect() in case we are redirected. For this reason, we store it here.
339     d->m_response.updateFromSoupMessage(message);
340 }
341
342 static void applyAuthenticationToRequest(ResourceHandle* handle, ResourceRequest& request, bool redirect)
343 {
344     // m_user/m_pass are credentials given manually, for instance, by the arguments passed to XMLHttpRequest.open().
345     ResourceHandleInternal* d = handle->getInternal();
346
347     if (handle->shouldUseCredentialStorage()) {
348         if (d->m_user.isEmpty() && d->m_pass.isEmpty())
349             d->m_initialCredential = CredentialStorage::get(request.url());
350         else if (!redirect) {
351             // If there is already a protection space known for the URL, update stored credentials
352             // before sending a request. This makes it possible to implement logout by sending an
353             // XMLHttpRequest with known incorrect credentials, and aborting it immediately (so that
354             // an authentication dialog doesn't pop up).
355             CredentialStorage::set(Credential(d->m_user, d->m_pass, CredentialPersistenceNone), request.url());
356         }
357     }
358
359     String user = d->m_user;
360     String password = d->m_pass;
361     if (!d->m_initialCredential.isEmpty()) {
362         user = d->m_initialCredential.user();
363         password = d->m_initialCredential.password();
364     }
365
366     if (user.isEmpty() && password.isEmpty()) {
367         // In case credential is not available from the handle and credential storage should not to be used,
368         // disable authentication manager so that credentials stored in libsoup are not used.
369         d->m_useAuthenticationManager = handle->shouldUseCredentialStorage();
370         return;
371     }
372
373     // We always put the credentials into the URL. In the CFNetwork-port HTTP family credentials are applied in
374     // the didReceiveAuthenticationChallenge callback, but libsoup requires us to use this method to override
375     // any previously remembered credentials. It has its own per-session credential storage.
376     URL urlWithCredentials(request.url());
377     urlWithCredentials.setUser(user);
378     urlWithCredentials.setPass(password);
379     request.setURL(urlWithCredentials);
380 }
381
382 #if ENABLE(WEB_TIMING)
383 // Called each time the message is going to be sent again except the first time.
384 // This happens when libsoup handles HTTP authentication.
385 static void restartedCallback(SoupMessage*, gpointer data)
386 {
387     ResourceHandle* handle = static_cast<ResourceHandle*>(data);
388     if (!handle || handle->cancelledOrClientless())
389         return;
390
391     ResourceHandleInternal* d = handle->getInternal();
392     ResourceResponse& redirectResponse = d->m_response;
393     redirectResponse.setResourceLoadTiming(ResourceLoadTiming::create());
394     redirectResponse.resourceLoadTiming()->requestTime = monotonicallyIncreasingTime();
395 }
396 #endif
397
398 static bool shouldRedirect(ResourceHandle* handle)
399 {
400     ResourceHandleInternal* d = handle->getInternal();
401     SoupMessage* message = d->m_soupMessage.get();
402
403     // Some 3xx status codes aren't actually redirects.
404     if (message->status_code == 300 || message->status_code == 304 || message->status_code == 305 || message->status_code == 306)
405         return false;
406
407     if (!soup_message_headers_get_one(message->response_headers, "Location"))
408         return false;
409
410     return true;
411 }
412
413 static bool shouldRedirectAsGET(SoupMessage* message, URL& newURL, bool crossOrigin)
414 {
415     if (message->method == SOUP_METHOD_GET || message->method == SOUP_METHOD_HEAD)
416         return false;
417
418     if (!newURL.protocolIsInHTTPFamily())
419         return true;
420
421     switch (message->status_code) {
422     case SOUP_STATUS_SEE_OTHER:
423         return true;
424     case SOUP_STATUS_FOUND:
425     case SOUP_STATUS_MOVED_PERMANENTLY:
426         if (message->method == SOUP_METHOD_POST)
427             return true;
428         break;
429     }
430
431     if (crossOrigin && message->method == SOUP_METHOD_DELETE)
432         return true;
433
434     return false;
435 }
436
437 static void continueAfterWillSendRequest(ResourceHandle* handle, const ResourceRequest& request)
438 {
439     // willSendRequest might cancel the load.
440     if (handle->cancelledOrClientless())
441         return;
442
443     ResourceRequest newRequest(request);
444     ResourceHandleInternal* d = handle->getInternal();
445     if (protocolHostAndPortAreEqual(newRequest.url(), d->m_response.url()))
446         applyAuthenticationToRequest(handle, newRequest, true);
447
448     if (!createSoupRequestAndMessageForHandle(handle, newRequest, true)) {
449         d->client()->cannotShowURL(handle);
450         return;
451     }
452
453     handle->sendPendingRequest();
454 }
455
456 static void doRedirect(ResourceHandle* handle)
457 {
458     ResourceHandleInternal* d = handle->getInternal();
459     static const int maxRedirects = 20;
460
461     if (d->m_redirectCount++ > maxRedirects) {
462         d->client()->didFail(handle, ResourceError::transportError(d->m_soupRequest.get(), SOUP_STATUS_TOO_MANY_REDIRECTS, "Too many redirects"));
463         cleanupSoupRequestOperation(handle);
464         return;
465     }
466
467     ResourceRequest newRequest = handle->firstRequest();
468     SoupMessage* message = d->m_soupMessage.get();
469     const char* location = soup_message_headers_get_one(message->response_headers, "Location");
470     URL newURL = URL(URL(soup_message_get_uri(message)), location);
471     bool crossOrigin = !protocolHostAndPortAreEqual(handle->firstRequest().url(), newURL);
472     newRequest.setURL(newURL);
473     newRequest.setFirstPartyForCookies(newURL);
474
475     if (newRequest.httpMethod() != "GET") {
476         // Change newRequest method to GET if change was made during a previous redirection
477         // or if current redirection says so
478         if (message->method == SOUP_METHOD_GET || shouldRedirectAsGET(message, newURL, crossOrigin)) {
479             newRequest.setHTTPMethod("GET");
480             newRequest.setHTTPBody(0);
481             newRequest.clearHTTPContentType();
482         }
483     }
484
485     // Should not set Referer after a redirect from a secure resource to non-secure one.
486     if (!newURL.protocolIs("https") && protocolIs(newRequest.httpReferrer(), "https") && handle->context()->shouldClearReferrerOnHTTPSToHTTPRedirect())
487         newRequest.clearHTTPReferrer();
488
489     d->m_user = newURL.user();
490     d->m_pass = newURL.pass();
491     newRequest.removeCredentials();
492
493     if (crossOrigin) {
494         // If the network layer carries over authentication headers from the original request
495         // in a cross-origin redirect, we want to clear those headers here. 
496         newRequest.clearHTTPAuthorization();
497
498         // TODO: We are losing any username and password specified in the redirect URL, as this is the 
499         // same behavior as the CFNet port. We should investigate if this is really what we want.
500     }
501
502     cleanupSoupRequestOperation(handle);
503
504     if (d->client()->usesAsyncCallbacks())
505         d->client()->willSendRequestAsync(handle, newRequest, d->m_response);
506     else {
507         d->client()->willSendRequest(handle, newRequest, d->m_response);
508         continueAfterWillSendRequest(handle, newRequest);
509     }
510
511 }
512
513 static void redirectSkipCallback(GObject*, GAsyncResult* asyncResult, gpointer data)
514 {
515     RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(data);
516
517     if (handle->cancelledOrClientless()) {
518         cleanupSoupRequestOperation(handle.get());
519         return;
520     }
521
522     GUniqueOutPtr<GError> error;
523     ResourceHandleInternal* d = handle->getInternal();
524     gssize bytesSkipped = g_input_stream_skip_finish(d->m_inputStream.get(), asyncResult, &error.outPtr());
525     if (error) {
526         handle->client()->didFail(handle.get(), ResourceError::genericGError(error.get(), d->m_soupRequest.get()));
527         cleanupSoupRequestOperation(handle.get());
528         return;
529     }
530
531     if (bytesSkipped > 0) {
532         g_input_stream_skip_async(d->m_inputStream.get(), gDefaultReadBufferSize, G_PRIORITY_DEFAULT,
533             d->m_cancellable.get(), redirectSkipCallback, handle.get());
534         return;
535     }
536
537     g_input_stream_close(d->m_inputStream.get(), 0, 0);
538     doRedirect(handle.get());
539 }
540
541 static void wroteBodyDataCallback(SoupMessage*, SoupBuffer* buffer, gpointer data)
542 {
543     RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(data);
544     if (!handle)
545         return;
546
547     ASSERT(buffer);
548     ResourceHandleInternal* d = handle->getInternal();
549     d->m_bodyDataSent += buffer->length;
550
551     if (handle->cancelledOrClientless())
552         return;
553
554     handle->client()->didSendData(handle.get(), d->m_bodyDataSent, d->m_bodySize);
555 }
556
557 static void cleanupSoupRequestOperation(ResourceHandle* handle, bool isDestroying)
558 {
559     ResourceHandleInternal* d = handle->getInternal();
560
561     d->m_soupRequest.clear();
562     d->m_inputStream.clear();
563     d->m_multipartInputStream.clear();
564     d->m_cancellable.clear();
565     d->m_soupBuffer.reset();
566
567     if (d->m_soupMessage) {
568         g_signal_handlers_disconnect_matched(d->m_soupMessage.get(), G_SIGNAL_MATCH_DATA,
569                                              0, 0, 0, 0, handle);
570         g_object_set_data(G_OBJECT(d->m_soupMessage.get()), "handle", 0);
571         d->m_soupMessage.clear();
572     }
573
574     if (d->m_timeoutSource) {
575         g_source_destroy(d->m_timeoutSource.get());
576         d->m_timeoutSource.clear();
577     }
578
579     if (!isDestroying)
580         handle->deref();
581 }
582
583 static bool handleUnignoredTLSErrors(ResourceHandle* handle)
584 {
585     ResourceHandleInternal* d = handle->getInternal();
586     const ResourceResponse& response = d->m_response;
587
588     if (!response.soupMessageTLSErrors() || gIgnoreSSLErrors)
589         return false;
590
591     String lowercaseHostURL = handle->firstRequest().url().host().lower();
592     if (allowsAnyHTTPSCertificateHosts().contains(lowercaseHostURL))
593         return false;
594
595     // We aren't ignoring errors globally, but the user may have already decided to accept this certificate.
596     CertificatesMap::iterator i = clientCertificates().find(lowercaseHostURL);
597     if (i != clientCertificates().end() && i->value.contains(response.soupMessageCertificate()))
598         return false;
599
600     handle->client()->didFail(handle, ResourceError::tlsError(d->m_soupRequest.get(), response.soupMessageTLSErrors(), response.soupMessageCertificate()));
601     return true;
602 }
603
604 size_t ResourceHandle::currentStreamPosition() const
605 {
606     GInputStream* baseStream = d->m_inputStream.get();
607     while (!G_IS_SEEKABLE(baseStream) && G_IS_FILTER_INPUT_STREAM(baseStream))
608         baseStream = g_filter_input_stream_get_base_stream(G_FILTER_INPUT_STREAM(baseStream));
609
610     if (!G_IS_SEEKABLE(baseStream))
611         return 0;
612
613     return g_seekable_tell(G_SEEKABLE(baseStream));
614 }
615
616 static void nextMultipartResponsePartCallback(GObject* /*source*/, GAsyncResult* result, gpointer data)
617 {
618     RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(data);
619
620     if (handle->cancelledOrClientless()) {
621         cleanupSoupRequestOperation(handle.get());
622         return;
623     }
624
625     ResourceHandleInternal* d = handle->getInternal();
626     ASSERT(!d->m_inputStream);
627
628     GUniqueOutPtr<GError> error;
629     d->m_inputStream = adoptGRef(soup_multipart_input_stream_next_part_finish(d->m_multipartInputStream.get(), result, &error.outPtr()));
630
631     if (error) {
632         handle->client()->didFail(handle.get(), ResourceError::httpError(d->m_soupMessage.get(), error.get(), d->m_soupRequest.get()));
633         cleanupSoupRequestOperation(handle.get());
634         return;
635     }
636
637     if (!d->m_inputStream) {
638         handle->client()->didFinishLoading(handle.get(), 0);
639         cleanupSoupRequestOperation(handle.get());
640         return;
641     }
642
643     d->m_response = ResourceResponse();
644     d->m_response.setURL(handle->firstRequest().url());
645     d->m_response.updateFromSoupMessageHeaders(soup_multipart_input_stream_get_headers(d->m_multipartInputStream.get()));
646
647     d->m_previousPosition = 0;
648
649     if (handle->client()->usesAsyncCallbacks())
650         handle->client()->didReceiveResponseAsync(handle.get(), d->m_response);
651     else {
652         handle->client()->didReceiveResponse(handle.get(), d->m_response);
653         continueAfterDidReceiveResponse(handle.get());
654     }
655 }
656
657 static void sendRequestCallback(GObject*, GAsyncResult* result, gpointer data)
658 {
659     RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(data);
660
661     if (handle->cancelledOrClientless()) {
662         cleanupSoupRequestOperation(handle.get());
663         return;
664     }
665
666     ResourceHandleInternal* d = handle->getInternal();
667     SoupMessage* soupMessage = d->m_soupMessage.get();
668
669
670     if (d->m_defersLoading) {
671         d->m_deferredResult = result;
672         return;
673     }
674
675     GUniqueOutPtr<GError> error;
676     GRefPtr<GInputStream> inputStream = adoptGRef(soup_request_send_finish(d->m_soupRequest.get(), result, &error.outPtr()));
677     if (error) {
678         handle->client()->didFail(handle.get(), ResourceError::httpError(soupMessage, error.get(), d->m_soupRequest.get()));
679         cleanupSoupRequestOperation(handle.get());
680         return;
681     }
682
683     if (soupMessage) {
684         if (SOUP_STATUS_IS_REDIRECTION(soupMessage->status_code) && shouldRedirect(handle.get())) {
685             d->m_inputStream = inputStream;
686             g_input_stream_skip_async(d->m_inputStream.get(), gDefaultReadBufferSize, G_PRIORITY_DEFAULT,
687                 d->m_cancellable.get(), redirectSkipCallback, handle.get());
688             return;
689         }
690
691         if (handle->shouldContentSniff() && soupMessage->status_code != SOUP_STATUS_NOT_MODIFIED) {
692             const char* sniffedType = soup_request_get_content_type(d->m_soupRequest.get());
693             d->m_response.setSniffedContentType(sniffedType);
694         }
695         d->m_response.updateFromSoupMessage(soupMessage);
696
697         if (handleUnignoredTLSErrors(handle.get())) {
698             cleanupSoupRequestOperation(handle.get());
699             return;
700         }
701
702     } else {
703         d->m_response.setURL(handle->firstRequest().url());
704         const gchar* contentType = soup_request_get_content_type(d->m_soupRequest.get());
705         d->m_response.setMimeType(extractMIMETypeFromMediaType(contentType));
706         d->m_response.setTextEncodingName(extractCharsetFromMediaType(contentType));
707         d->m_response.setExpectedContentLength(soup_request_get_content_length(d->m_soupRequest.get()));
708     }
709
710     if (soupMessage && d->m_response.isMultipart())
711         d->m_multipartInputStream = adoptGRef(soup_multipart_input_stream_new(soupMessage, inputStream.get()));
712     else
713         d->m_inputStream = inputStream;
714
715     if (d->client()->usesAsyncCallbacks())
716         handle->client()->didReceiveResponseAsync(handle.get(), d->m_response);
717     else {
718         handle->client()->didReceiveResponse(handle.get(), d->m_response);
719         continueAfterDidReceiveResponse(handle.get());
720     }
721 }
722
723 static void continueAfterDidReceiveResponse(ResourceHandle* handle)
724 {
725     if (handle->cancelledOrClientless()) {
726         cleanupSoupRequestOperation(handle);
727         return;
728     }
729
730     ResourceHandleInternal* d = handle->getInternal();
731     if (d->m_soupMessage && d->m_multipartInputStream && !d->m_inputStream) {
732         soup_multipart_input_stream_next_part_async(d->m_multipartInputStream.get(), G_PRIORITY_DEFAULT,
733             d->m_cancellable.get(), nextMultipartResponsePartCallback, handle);
734         return;
735     }
736
737     ASSERT(d->m_inputStream);
738     handle->ensureReadBuffer();
739     g_input_stream_read_async(d->m_inputStream.get(), const_cast<char*>(d->m_soupBuffer->data), d->m_soupBuffer->length,
740         G_PRIORITY_DEFAULT, d->m_cancellable.get(), readCallback, handle);
741 }
742
743 static bool addFileToSoupMessageBody(SoupMessage* message, const String& fileNameString, size_t offset, size_t lengthToSend, unsigned long& totalBodySize)
744 {
745     GUniqueOutPtr<GError> error;
746     CString fileName = fileSystemRepresentation(fileNameString);
747     GMappedFile* fileMapping = g_mapped_file_new(fileName.data(), false, &error.outPtr());
748     if (error)
749         return false;
750
751     gsize bufferLength = lengthToSend;
752     if (!lengthToSend)
753         bufferLength = g_mapped_file_get_length(fileMapping);
754     totalBodySize += bufferLength;
755
756     SoupBuffer* soupBuffer = soup_buffer_new_with_owner(g_mapped_file_get_contents(fileMapping) + offset,
757                                                         bufferLength,
758                                                         fileMapping,
759                                                         reinterpret_cast<GDestroyNotify>(g_mapped_file_unref));
760     soup_message_body_append_buffer(message->request_body, soupBuffer);
761     soup_buffer_free(soupBuffer);
762     return true;
763 }
764
765 #if ENABLE(BLOB)
766 static bool blobIsOutOfDate(const BlobDataItem& blobItem)
767 {
768     ASSERT(blobItem.type == BlobDataItem::File);
769     if (!isValidFileTime(blobItem.expectedModificationTime))
770         return false;
771
772     time_t fileModificationTime;
773     if (!getFileModificationTime(blobItem.path, fileModificationTime))
774         return true;
775
776     return fileModificationTime != static_cast<time_t>(blobItem.expectedModificationTime);
777 }
778
779 static void addEncodedBlobItemToSoupMessageBody(SoupMessage* message, const BlobDataItem& blobItem, unsigned long& totalBodySize)
780 {
781     if (blobItem.type == BlobDataItem::Data) {
782         totalBodySize += blobItem.length;
783         soup_message_body_append(message->request_body, SOUP_MEMORY_TEMPORARY,
784                                  blobItem.data->data() + blobItem.offset, blobItem.length);
785         return;
786     }
787
788     ASSERT(blobItem.type == BlobDataItem::File);
789     if (blobIsOutOfDate(blobItem))
790         return;
791
792     addFileToSoupMessageBody(message,
793                              blobItem.path,
794                              blobItem.offset,
795                              blobItem.length == BlobDataItem::toEndOfFile ? 0 : blobItem.length,
796                              totalBodySize);
797 }
798
799 static void addEncodedBlobToSoupMessageBody(SoupMessage* message, const FormDataElement& element, unsigned long& totalBodySize)
800 {
801     RefPtr<BlobStorageData> blobData = static_cast<BlobRegistryImpl&>(blobRegistry()).getBlobDataFromURL(URL(ParsedURLString, element.m_url));
802     if (!blobData)
803         return;
804
805     for (size_t i = 0; i < blobData->items().size(); ++i)
806         addEncodedBlobItemToSoupMessageBody(message, blobData->items()[i], totalBodySize);
807 }
808 #endif // ENABLE(BLOB)
809
810 static bool addFormElementsToSoupMessage(SoupMessage* message, const char*, FormData* httpBody, unsigned long& totalBodySize)
811 {
812     soup_message_body_set_accumulate(message->request_body, FALSE);
813     size_t numElements = httpBody->elements().size();
814     for (size_t i = 0; i < numElements; i++) {
815         const FormDataElement& element = httpBody->elements()[i];
816
817         if (element.m_type == FormDataElement::Type::Data) {
818             totalBodySize += element.m_data.size();
819             soup_message_body_append(message->request_body, SOUP_MEMORY_TEMPORARY,
820                                      element.m_data.data(), element.m_data.size());
821             continue;
822         }
823
824         if (element.m_type == FormDataElement::Type::EncodedFile) {
825             if (!addFileToSoupMessageBody(message ,
826                                          element.m_filename,
827                                          0 /* offset */,
828                                          0 /* lengthToSend */,
829                                          totalBodySize))
830                 return false;
831             continue;
832         }
833
834 #if ENABLE(BLOB)
835         ASSERT(element.m_type == FormDataElement::Type::EncodedBlob);
836         addEncodedBlobToSoupMessageBody(message, element, totalBodySize);
837 #endif
838     }
839     return true;
840 }
841
842 #if ENABLE(WEB_TIMING)
843 static int milisecondsSinceRequest(double requestTime)
844 {
845     return static_cast<int>((monotonicallyIncreasingTime() - requestTime) * 1000.0);
846 }
847
848 static void wroteBodyCallback(SoupMessage*, gpointer data)
849 {
850     RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(data);
851     if (!handle)
852         return;
853
854     ResourceHandleInternal* d = handle->getInternal();
855     if (!d->m_response.resourceLoadTiming())
856         return;
857
858     d->m_response.resourceLoadTiming()->sendEnd = milisecondsSinceRequest(d->m_response.resourceLoadTiming()->requestTime);
859 }
860
861 void ResourceHandle::didStartRequest()
862 {
863     ResourceHandleInternal* d = getInternal();
864     if (!d->m_response.resourceLoadTiming())
865         return;
866
867     d->m_response.resourceLoadTiming()->sendStart = milisecondsSinceRequest(d->m_response.resourceLoadTiming()->requestTime);
868     if (d->m_response.resourceLoadTiming()->sslStart != -1) {
869         // WebCore/inspector/front-end/RequestTimingView.js assumes
870         // that SSL time is included in connection time so must
871         // substract here the SSL delta that will be added later (see
872         // WebInspector.RequestTimingView.createTimingTable in the
873         // file above for more details).
874         d->m_response.resourceLoadTiming()->sendStart -=
875             d->m_response.resourceLoadTiming()->sslEnd - d->m_response.resourceLoadTiming()->sslStart;
876     }
877 }
878
879 static void networkEventCallback(SoupMessage*, GSocketClientEvent event, GIOStream*, gpointer data)
880 {
881     ResourceHandle* handle = static_cast<ResourceHandle*>(data);
882     if (!handle)
883         return;
884
885     if (handle->cancelledOrClientless())
886         return;
887
888     ResourceHandleInternal* d = handle->getInternal();
889     int deltaTime = milisecondsSinceRequest(d->m_response.resourceLoadTiming()->requestTime);
890     switch (event) {
891     case G_SOCKET_CLIENT_RESOLVING:
892         d->m_response.resourceLoadTiming()->dnsStart = deltaTime;
893         break;
894     case G_SOCKET_CLIENT_RESOLVED:
895         d->m_response.resourceLoadTiming()->dnsEnd = deltaTime;
896         break;
897     case G_SOCKET_CLIENT_CONNECTING:
898         d->m_response.resourceLoadTiming()->connectStart = deltaTime;
899         if (d->m_response.resourceLoadTiming()->dnsStart != -1)
900             // WebCore/inspector/front-end/RequestTimingView.js assumes
901             // that DNS time is included in connection time so must
902             // substract here the DNS delta that will be added later (see
903             // WebInspector.RequestTimingView.createTimingTable in the
904             // file above for more details).
905             d->m_response.resourceLoadTiming()->connectStart -=
906                 d->m_response.resourceLoadTiming()->dnsEnd - d->m_response.resourceLoadTiming()->dnsStart;
907         break;
908     case G_SOCKET_CLIENT_CONNECTED:
909         // Web Timing considers that connection time involves dns, proxy & TLS negotiation...
910         // so we better pick G_SOCKET_CLIENT_COMPLETE for connectEnd
911         break;
912     case G_SOCKET_CLIENT_PROXY_NEGOTIATING:
913         d->m_response.resourceLoadTiming()->proxyStart = deltaTime;
914         break;
915     case G_SOCKET_CLIENT_PROXY_NEGOTIATED:
916         d->m_response.resourceLoadTiming()->proxyEnd = deltaTime;
917         break;
918     case G_SOCKET_CLIENT_TLS_HANDSHAKING:
919         d->m_response.resourceLoadTiming()->sslStart = deltaTime;
920         break;
921     case G_SOCKET_CLIENT_TLS_HANDSHAKED:
922         d->m_response.resourceLoadTiming()->sslEnd = deltaTime;
923         break;
924     case G_SOCKET_CLIENT_COMPLETE:
925         d->m_response.resourceLoadTiming()->connectEnd = deltaTime;
926         break;
927     default:
928         ASSERT_NOT_REACHED();
929         break;
930     }
931 }
932 #endif
933
934 static bool createSoupMessageForHandleAndRequest(ResourceHandle* handle, const ResourceRequest& request)
935 {
936     ASSERT(handle);
937
938     ResourceHandleInternal* d = handle->getInternal();
939     ASSERT(d->m_soupRequest);
940
941     d->m_soupMessage = adoptGRef(soup_request_http_get_message(SOUP_REQUEST_HTTP(d->m_soupRequest.get())));
942     if (!d->m_soupMessage)
943         return false;
944
945     SoupMessage* soupMessage = d->m_soupMessage.get();
946     request.updateSoupMessage(soupMessage);
947
948     g_object_set_data(G_OBJECT(soupMessage), "handle", handle);
949     if (!handle->shouldContentSniff())
950         soup_message_disable_feature(soupMessage, SOUP_TYPE_CONTENT_SNIFFER);
951     if (!d->m_useAuthenticationManager)
952         soup_message_disable_feature(soupMessage, SOUP_TYPE_AUTH_MANAGER);
953
954     FormData* httpBody = request.httpBody();
955     CString contentType = request.httpContentType().utf8().data();
956     if (httpBody && !httpBody->isEmpty() && !addFormElementsToSoupMessage(soupMessage, contentType.data(), httpBody, d->m_bodySize)) {
957         // We failed to prepare the body data, so just fail this load.
958         d->m_soupMessage.clear();
959         return false;
960     }
961
962     // Make sure we have an Accept header for subresources; some sites
963     // want this to serve some of their subresources
964     if (!soup_message_headers_get_one(soupMessage->request_headers, "Accept"))
965         soup_message_headers_append(soupMessage->request_headers, "Accept", "*/*");
966
967     // In the case of XHR .send() and .send("") explicitly tell libsoup to send a zero content-lenght header
968     // for consistency with other backends (e.g. Chromium's) and other UA implementations like FF. It's done
969     // in the backend here instead of in XHR code since in XHR CORS checking prevents us from this kind of
970     // late header manipulation.
971     if ((request.httpMethod() == "POST" || request.httpMethod() == "PUT")
972         && (!request.httpBody() || request.httpBody()->isEmpty()))
973         soup_message_headers_set_content_length(soupMessage->request_headers, 0);
974
975     g_signal_connect(d->m_soupMessage.get(), "got-headers", G_CALLBACK(gotHeadersCallback), handle);
976     g_signal_connect(d->m_soupMessage.get(), "wrote-body-data", G_CALLBACK(wroteBodyDataCallback), handle);
977
978     soup_message_set_flags(d->m_soupMessage.get(), static_cast<SoupMessageFlags>(soup_message_get_flags(d->m_soupMessage.get()) | SOUP_MESSAGE_NO_REDIRECT));
979
980 #if ENABLE(WEB_TIMING)
981     d->m_response.setResourceLoadTiming(ResourceLoadTiming::create());
982     g_signal_connect(d->m_soupMessage.get(), "network-event", G_CALLBACK(networkEventCallback), handle);
983     g_signal_connect(d->m_soupMessage.get(), "restarted", G_CALLBACK(restartedCallback), handle);
984     g_signal_connect(d->m_soupMessage.get(), "wrote-body", G_CALLBACK(wroteBodyCallback), handle);
985 #endif
986
987 #if SOUP_CHECK_VERSION(2, 43, 1)
988     soup_message_set_priority(d->m_soupMessage.get(), toSoupMessagePriority(request.priority()));
989 #endif
990
991     return true;
992 }
993
994 static bool createSoupRequestAndMessageForHandle(ResourceHandle* handle, const ResourceRequest& request, bool isHTTPFamilyRequest)
995 {
996     ResourceHandleInternal* d = handle->getInternal();
997
998     GUniquePtr<SoupURI> soupURI = request.createSoupURI();
999     if (!soupURI)
1000         return false;
1001
1002     GUniqueOutPtr<GError> error;
1003     d->m_soupRequest = adoptGRef(soup_session_request_uri(d->soupSession(), soupURI.get(), &error.outPtr()));
1004     if (error) {
1005         d->m_soupRequest.clear();
1006         return false;
1007     }
1008
1009     // SoupMessages are only applicable to HTTP-family requests.
1010     if (isHTTPFamilyRequest && !createSoupMessageForHandleAndRequest(handle, request)) {
1011         d->m_soupRequest.clear();
1012         return false;
1013     }
1014
1015     request.updateSoupRequest(d->m_soupRequest.get());
1016
1017     return true;
1018 }
1019
1020 bool ResourceHandle::start()
1021 {
1022     ASSERT(!d->m_soupMessage);
1023
1024     // The frame could be null if the ResourceHandle is not associated to any
1025     // Frame, e.g. if we are downloading a file.
1026     // If the frame is not null but the page is null this must be an attempted
1027     // load from an unload handler, so let's just block it.
1028     // If both the frame and the page are not null the context is valid.
1029     if (d->m_context && !d->m_context->isValid())
1030         return false;
1031
1032     // Only allow the POST and GET methods for non-HTTP requests.
1033     const ResourceRequest& request = firstRequest();
1034     bool isHTTPFamilyRequest = request.url().protocolIsInHTTPFamily();
1035     if (!isHTTPFamilyRequest && request.httpMethod() != "GET" && request.httpMethod() != "POST") {
1036         this->scheduleFailure(InvalidURLFailure); // Error must not be reported immediately
1037         return true;
1038     }
1039
1040     applyAuthenticationToRequest(this, firstRequest(), false);
1041
1042     if (!createSoupRequestAndMessageForHandle(this, request, isHTTPFamilyRequest)) {
1043         this->scheduleFailure(InvalidURLFailure); // Error must not be reported immediately
1044         return true;
1045     }
1046
1047     // Send the request only if it's not been explicitly deferred.
1048     if (!d->m_defersLoading)
1049         sendPendingRequest();
1050
1051     return true;
1052 }
1053
1054 void ResourceHandle::sendPendingRequest()
1055 {
1056 #if ENABLE(WEB_TIMING)
1057     if (d->m_response.resourceLoadTiming())
1058         d->m_response.resourceLoadTiming()->requestTime = monotonicallyIncreasingTime();
1059 #endif
1060
1061     if (d->m_firstRequest.timeoutInterval() > 0) {
1062         // soup_add_timeout returns a GSource* whose only reference is owned by
1063         // the context. We need to have our own reference to it, hence not using adoptRef.
1064         d->m_timeoutSource = soup_add_timeout(g_main_context_get_thread_default(),
1065             d->m_firstRequest.timeoutInterval() * 1000, requestTimeoutCallback, this);
1066     }
1067
1068     // Balanced by a deref() in cleanupSoupRequestOperation, which should always run.
1069     ref();
1070
1071     d->m_cancellable = adoptGRef(g_cancellable_new());
1072     soup_request_send_async(d->m_soupRequest.get(), d->m_cancellable.get(), sendRequestCallback, this);
1073 }
1074
1075 void ResourceHandle::cancel()
1076 {
1077     d->m_cancelled = true;
1078     if (d->m_soupMessage)
1079         soup_session_cancel_message(d->soupSession(), d->m_soupMessage.get(), SOUP_STATUS_CANCELLED);
1080     else if (d->m_cancellable)
1081         g_cancellable_cancel(d->m_cancellable.get());
1082 }
1083
1084 bool ResourceHandle::shouldUseCredentialStorage()
1085 {
1086     return (!client() || client()->shouldUseCredentialStorage(this)) && firstRequest().url().protocolIsInHTTPFamily();
1087 }
1088
1089 void ResourceHandle::setHostAllowsAnyHTTPSCertificate(const String& host)
1090 {
1091     allowsAnyHTTPSCertificateHosts().add(host.lower());
1092 }
1093
1094 void ResourceHandle::setClientCertificate(const String& host, GTlsCertificate* certificate)
1095 {
1096     clientCertificates().add(host.lower(), HostTLSCertificateSet()).iterator->value.add(certificate);
1097 }
1098
1099 void ResourceHandle::setIgnoreSSLErrors(bool ignoreSSLErrors)
1100 {
1101     gIgnoreSSLErrors = ignoreSSLErrors;
1102 }
1103
1104 #if PLATFORM(GTK)
1105 void getCredentialFromPersistentStoreCallback(const Credential& credential, void* data)
1106 {
1107     static_cast<ResourceHandle*>(data)->continueDidReceiveAuthenticationChallenge(credential);
1108 }
1109 #endif
1110
1111 void ResourceHandle::continueDidReceiveAuthenticationChallenge(const Credential& credentialFromPersistentStorage)
1112 {
1113     ASSERT(!d->m_currentWebChallenge.isNull());
1114     AuthenticationChallenge& challenge = d->m_currentWebChallenge;
1115
1116     ASSERT(challenge.soupSession());
1117     ASSERT(challenge.soupMessage());
1118     if (!credentialFromPersistentStorage.isEmpty())
1119         challenge.setProposedCredential(credentialFromPersistentStorage);
1120
1121     if (!client()) {
1122         soup_session_unpause_message(challenge.soupSession(), challenge.soupMessage());
1123         clearAuthentication();
1124         return;
1125     }
1126
1127     ASSERT(challenge.soupSession());
1128     ASSERT(challenge.soupMessage());
1129     client()->didReceiveAuthenticationChallenge(this, challenge);
1130 }
1131
1132 void ResourceHandle::didReceiveAuthenticationChallenge(const AuthenticationChallenge& challenge)
1133 {
1134     ASSERT(d->m_currentWebChallenge.isNull());
1135
1136     // FIXME: Per the specification, the user shouldn't be asked for credentials if there were incorrect ones provided explicitly.
1137     bool useCredentialStorage = shouldUseCredentialStorage();
1138     if (useCredentialStorage) {
1139         if (!d->m_initialCredential.isEmpty() || challenge.previousFailureCount()) {
1140             // The stored credential wasn't accepted, stop using it. There is a race condition
1141             // here, since a different credential might have already been stored by another
1142             // ResourceHandle, but the observable effect should be very minor, if any.
1143             CredentialStorage::remove(challenge.protectionSpace());
1144         }
1145
1146         if (!challenge.previousFailureCount()) {
1147             Credential credential = CredentialStorage::get(challenge.protectionSpace());
1148             if (!credential.isEmpty() && credential != d->m_initialCredential) {
1149                 ASSERT(credential.persistence() == CredentialPersistenceNone);
1150
1151                 // Store the credential back, possibly adding it as a default for this directory.
1152                 if (isAuthenticationFailureStatusCode(challenge.failureResponse().httpStatusCode()))
1153                     CredentialStorage::set(credential, challenge.protectionSpace(), challenge.failureResponse().url());
1154
1155                 soup_auth_authenticate(challenge.soupAuth(), credential.user().utf8().data(), credential.password().utf8().data());
1156                 return;
1157             }
1158         }
1159     }
1160
1161     d->m_currentWebChallenge = challenge;
1162     soup_session_pause_message(challenge.soupSession(), challenge.soupMessage());
1163
1164 #if PLATFORM(GTK)
1165     // We could also do this before we even start the request, but that would be at the expense
1166     // of all request latency, versus a one-time latency for the small subset of requests that
1167     // use HTTP authentication. In the end, this doesn't matter much, because persistent credentials
1168     // will become session credentials after the first use.
1169     if (useCredentialStorage) {
1170         credentialBackingStore().credentialForChallenge(challenge, getCredentialFromPersistentStoreCallback, this);
1171         return;
1172     }
1173 #endif
1174
1175     continueDidReceiveAuthenticationChallenge(Credential());
1176 }
1177
1178 void ResourceHandle::receivedRequestToContinueWithoutCredential(const AuthenticationChallenge& challenge)
1179 {
1180     ASSERT(!challenge.isNull());
1181     if (challenge != d->m_currentWebChallenge)
1182         return;
1183     soup_session_unpause_message(challenge.soupSession(), challenge.soupMessage());
1184
1185     clearAuthentication();
1186 }
1187
1188 void ResourceHandle::receivedCredential(const AuthenticationChallenge& challenge, const Credential& credential)
1189 {
1190     ASSERT(!challenge.isNull());
1191     if (challenge != d->m_currentWebChallenge)
1192         return;
1193
1194     // FIXME: Support empty credentials. Currently, an empty credential cannot be stored in WebCore credential storage, as that's empty value for its map.
1195     if (credential.isEmpty()) {
1196         receivedRequestToContinueWithoutCredential(challenge);
1197         return;
1198     }
1199
1200     if (shouldUseCredentialStorage()) {
1201         // Eventually we will manage per-session credentials only internally or use some newly-exposed API from libsoup,
1202         // because once we authenticate via libsoup, there is no way to ignore it for a particular request. Right now,
1203         // we place the credentials in the store even though libsoup will never fire the authenticate signal again for
1204         // this protection space.
1205         if (credential.persistence() == CredentialPersistenceForSession || credential.persistence() == CredentialPersistencePermanent)
1206             CredentialStorage::set(credential, challenge.protectionSpace(), challenge.failureResponse().url());
1207
1208 #if PLATFORM(GTK)
1209         if (credential.persistence() == CredentialPersistencePermanent) {
1210             d->m_credentialDataToSaveInPersistentStore.credential = credential;
1211             d->m_credentialDataToSaveInPersistentStore.challenge = challenge;
1212         }
1213 #endif
1214     }
1215
1216     ASSERT(challenge.soupSession());
1217     ASSERT(challenge.soupMessage());
1218     soup_auth_authenticate(challenge.soupAuth(), credential.user().utf8().data(), credential.password().utf8().data());
1219     soup_session_unpause_message(challenge.soupSession(), challenge.soupMessage());
1220
1221     clearAuthentication();
1222 }
1223
1224 void ResourceHandle::receivedCancellation(const AuthenticationChallenge& challenge)
1225 {
1226     ASSERT(!challenge.isNull());
1227     if (challenge != d->m_currentWebChallenge)
1228         return;
1229
1230     if (cancelledOrClientless()) {
1231         clearAuthentication();
1232         return;
1233     }
1234
1235     ASSERT(challenge.soupSession());
1236     ASSERT(challenge.soupMessage());
1237     soup_session_unpause_message(challenge.soupSession(), challenge.soupMessage());
1238
1239     if (client())
1240         client()->receivedCancellation(this, challenge);
1241
1242     clearAuthentication();
1243 }
1244
1245 static bool waitingToSendRequest(ResourceHandle* handle)
1246 {
1247     // We need to check for d->m_soupRequest because the request may have raised a failure
1248     // (for example invalid URLs). We cannot  simply check for d->m_scheduledFailure because
1249     // it's cleared as soon as the failure event is fired.
1250     return handle->getInternal()->m_soupRequest && !handle->getInternal()->m_cancellable;
1251 }
1252
1253 void ResourceHandle::platformSetDefersLoading(bool defersLoading)
1254 {
1255     if (cancelledOrClientless())
1256         return;
1257
1258     // Except when canceling a possible timeout timer, we only need to take action here to UN-defer loading.
1259     if (defersLoading) {
1260         if (d->m_timeoutSource) {
1261             g_source_destroy(d->m_timeoutSource.get());
1262             d->m_timeoutSource.clear();
1263         }
1264         return;
1265     }
1266
1267     if (waitingToSendRequest(this)) {
1268         sendPendingRequest();
1269         return;
1270     }
1271
1272     if (d->m_deferredResult) {
1273         GRefPtr<GAsyncResult> asyncResult = adoptGRef(d->m_deferredResult.leakRef());
1274
1275         if (d->m_inputStream)
1276             readCallback(G_OBJECT(d->m_inputStream.get()), asyncResult.get(), this);
1277         else
1278             sendRequestCallback(G_OBJECT(d->m_soupRequest.get()), asyncResult.get(), this);
1279     }
1280 }
1281
1282 bool ResourceHandle::loadsBlocked()
1283 {
1284     return false;
1285 }
1286
1287 void ResourceHandle::platformLoadResourceSynchronously(NetworkingContext* context, const ResourceRequest& request, StoredCredentials storedCredentials, ResourceError& error, ResourceResponse& response, Vector<char>& data)
1288 {
1289     ASSERT(!loadingSynchronousRequest);
1290     if (loadingSynchronousRequest) // In practice this cannot happen, but if for some reason it does,
1291         return;                    // we want to avoid accidentally going into an infinite loop of requests.
1292
1293     WebCoreSynchronousLoader syncLoader(error, response, sessionFromContext(context), data, storedCredentials);
1294     RefPtr<ResourceHandle> handle = create(context, request, &syncLoader, false /*defersLoading*/, false /*shouldContentSniff*/);
1295     if (!handle)
1296         return;
1297
1298     // If the request has already failed, do not run the main loop, or else we'll block indefinitely.
1299     if (handle->d->m_scheduledFailureType != NoFailure)
1300         return;
1301
1302     syncLoader.run();
1303 }
1304
1305 static void readCallback(GObject*, GAsyncResult* asyncResult, gpointer data)
1306 {
1307     RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(data);
1308
1309     if (handle->cancelledOrClientless()) {
1310         cleanupSoupRequestOperation(handle.get());
1311         return;
1312     }
1313
1314     ResourceHandleInternal* d = handle->getInternal();
1315     if (d->m_defersLoading) {
1316         d->m_deferredResult = asyncResult;
1317         return;
1318     }
1319
1320     GUniqueOutPtr<GError> error;
1321     gssize bytesRead = g_input_stream_read_finish(d->m_inputStream.get(), asyncResult, &error.outPtr());
1322
1323     if (error) {
1324         handle->client()->didFail(handle.get(), ResourceError::genericGError(error.get(), d->m_soupRequest.get()));
1325         cleanupSoupRequestOperation(handle.get());
1326         return;
1327     }
1328
1329     if (!bytesRead) {
1330         // If this is a multipart message, we'll look for another part.
1331         if (d->m_soupMessage && d->m_multipartInputStream) {
1332             d->m_inputStream.clear();
1333             soup_multipart_input_stream_next_part_async(d->m_multipartInputStream.get(), G_PRIORITY_DEFAULT,
1334                 d->m_cancellable.get(), nextMultipartResponsePartCallback, handle.get());
1335             return;
1336         }
1337
1338         g_input_stream_close(d->m_inputStream.get(), 0, 0);
1339
1340         handle->client()->didFinishLoading(handle.get(), 0);
1341         cleanupSoupRequestOperation(handle.get());
1342         return;
1343     }
1344
1345     // It's mandatory to have sent a response before sending data
1346     ASSERT(!d->m_response.isNull());
1347
1348     size_t currentPosition = handle->currentStreamPosition();
1349     size_t encodedDataLength = currentPosition ? currentPosition - d->m_previousPosition : bytesRead;
1350
1351     ASSERT(d->m_soupBuffer);
1352     d->m_soupBuffer->length = bytesRead; // The buffer might be larger than the number of bytes read. SharedBuffer looks at the length property.
1353     handle->client()->didReceiveBuffer(handle.get(), SharedBuffer::wrapSoupBuffer(d->m_soupBuffer.release()), encodedDataLength);
1354
1355     d->m_previousPosition = currentPosition;
1356
1357     // didReceiveBuffer may cancel the load, which may release the last reference.
1358     if (handle->cancelledOrClientless()) {
1359         cleanupSoupRequestOperation(handle.get());
1360         return;
1361     }
1362
1363     handle->ensureReadBuffer();
1364     g_input_stream_read_async(d->m_inputStream.get(), const_cast<char*>(d->m_soupBuffer->data), d->m_soupBuffer->length, G_PRIORITY_DEFAULT,
1365         d->m_cancellable.get(), readCallback, handle.get());
1366 }
1367
1368 void ResourceHandle::continueWillSendRequest(const ResourceRequest& request)
1369 {
1370     ASSERT(client());
1371     ASSERT(client()->usesAsyncCallbacks());
1372     continueAfterWillSendRequest(this, request);
1373 }
1374
1375 void ResourceHandle::continueDidReceiveResponse()
1376 {
1377     ASSERT(client());
1378     ASSERT(client()->usesAsyncCallbacks());
1379     continueAfterDidReceiveResponse(this);
1380 }
1381
1382 static gboolean requestTimeoutCallback(gpointer data)
1383 {
1384     RefPtr<ResourceHandle> handle = static_cast<ResourceHandle*>(data);
1385     handle->client()->didFail(handle.get(), ResourceError::timeoutError(handle->getInternal()->m_firstRequest.url().string()));
1386     handle->cancel();
1387
1388     return FALSE;
1389 }
1390
1391 }
1392
1393 #endif