2009-03-05 Gustavo Noronha Silva <gns@gnome.org>
[WebKit-https.git] / WebKit / gtk / webkit / webkitdownload.cpp
1 /*
2  * Copyright (C) 2008 Collabora Ltd.
3  * Copyright (C) 2009 Gustavo Noronha Silva <gns@gnome.org>
4  *
5  * This library is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU Library General Public
7  * License as published by the Free Software Foundation; either
8  * version 2 of the License, or (at your option) any later version.
9  *
10  * This library is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
13  * Library General Public License for more details.
14  *
15  * You should have received a copy of the GNU Library General Public License
16  * along with this library; see the file COPYING.LIB.  If not, write to
17  * the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18  * Boston, MA 02110-1301, USA.
19  */
20
21 #include "config.h"
22
23 #include "CString.h"
24 #include "Noncopyable.h"
25 #include "NotImplemented.h"
26 #include "ResourceHandleClient.h"
27 #include "ResourceRequest.h"
28 #include "ResourceResponse.h"
29 #include "webkitdownload.h"
30 #include "webkitmarshal.h"
31 #include "webkitprivate.h"
32
33 #include <glib/gstdio.h>
34
35 using namespace WebKit;
36 using namespace WebCore;
37
38 class DownloadClient : Noncopyable, public ResourceHandleClient {
39     public:
40         DownloadClient(WebKitDownload*);
41
42         virtual void didReceiveResponse(ResourceHandle*, const ResourceResponse&);
43         virtual void didReceiveData(ResourceHandle*, const char*, int, int);
44         virtual void didFinishLoading(ResourceHandle*);
45         virtual void didFail(ResourceHandle*, const ResourceError&);
46         virtual void wasBlocked(ResourceHandle*);
47         virtual void cannotShowURL(ResourceHandle*);
48
49     private:
50         WebKitDownload* m_download;
51 };
52
53 extern "C" {
54
55 #define WEBKIT_DOWNLOAD_GET_PRIVATE(obj)    (G_TYPE_INSTANCE_GET_PRIVATE((obj), WEBKIT_TYPE_DOWNLOAD, WebKitDownloadPrivate))
56
57 struct _WebKitDownloadPrivate {
58     gchar* destinationURI;
59     gchar* suggestedFilename;
60     guint currentSize;
61     GTimer* timer;
62     WebKitDownloadState state;
63     GFileOutputStream* outputStream;
64     DownloadClient* downloadClient;
65     WebKitNetworkRequest* networkRequest;
66     ResourceResponse* networkResponse;
67     RefPtr<ResourceHandle> resourceHandle;
68 };
69
70 enum {
71     // Normal signals.
72     ERROR,
73     LAST_SIGNAL
74 };
75
76 static guint webkit_download_signals[LAST_SIGNAL] = { 0 };
77
78 enum {
79     PROP_0,
80
81     PROP_NETWORK_REQUEST,
82     PROP_DESTINATION_URI,
83     PROP_SUGGESTED_FILENAME,
84     PROP_PROGRESS,
85     PROP_CURRENT_SIZE,
86     PROP_TOTAL_SIZE
87 };
88
89 G_DEFINE_TYPE(WebKitDownload, webkit_download, G_TYPE_OBJECT);
90
91 static void webkit_download_dispose(GObject* object)
92 {
93     WebKitDownload* download = WEBKIT_DOWNLOAD(object);
94     WebKitDownloadPrivate* priv = download->priv;
95
96     if (priv->outputStream) {
97         g_object_unref(priv->outputStream);
98         priv->outputStream = NULL;
99     }
100
101     if (priv->networkRequest) {
102         g_object_unref(priv->networkRequest);
103         priv->networkRequest = NULL;
104     }
105
106     G_OBJECT_CLASS(webkit_download_parent_class)->dispose(object);
107 }
108
109 static void webkit_download_finalize(GObject* object)
110 {
111     WebKitDownload* download = WEBKIT_DOWNLOAD(object);
112     WebKitDownloadPrivate* priv = download->priv;
113
114     // We don't call webkit_download_cancel() because we don't want to emit
115     // signals when finalizing an object.
116     if (priv->resourceHandle) {
117         if (priv->state == WEBKIT_DOWNLOAD_STATE_STARTED) {
118             priv->resourceHandle->setClient(0);
119             priv->resourceHandle->cancel();
120         }
121         priv->resourceHandle.release();
122     }
123
124     delete priv->downloadClient;
125     delete priv->networkResponse;
126
127     // The download object may never have _start called on it, so we
128     // need to make sure timer is non-NULL.
129     if (priv->timer)
130         g_timer_destroy(priv->timer);
131
132     g_free(priv->destinationURI);
133     g_free(priv->suggestedFilename);
134
135     G_OBJECT_CLASS(webkit_download_parent_class)->finalize(object);
136 }
137
138 static void webkit_download_get_property(GObject* object, guint prop_id, GValue* value, GParamSpec* pspec)
139 {
140     WebKitDownload* download = WEBKIT_DOWNLOAD(object);
141
142     switch(prop_id) {
143     case PROP_NETWORK_REQUEST:
144         g_value_set_object(value, webkit_download_get_network_request(download));
145         break;
146     case PROP_DESTINATION_URI:
147         g_value_set_string(value, webkit_download_get_destination_uri(download));
148         break;
149     case PROP_SUGGESTED_FILENAME:
150         g_value_set_string(value, webkit_download_get_suggested_filename(download));
151         break;
152     case PROP_PROGRESS:
153         g_value_set_double(value, webkit_download_get_progress(download));
154         break;
155     case PROP_CURRENT_SIZE:
156         g_value_set_uint64(value, webkit_download_get_current_size(download));
157         break;
158     case PROP_TOTAL_SIZE:
159         g_value_set_uint64(value, webkit_download_get_total_size(download));
160         break;
161     default:
162         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
163     }
164 }
165
166 static void webkit_download_set_property(GObject* object, guint prop_id, const GValue* value, GParamSpec *pspec)
167 {
168     WebKitDownload* download = WEBKIT_DOWNLOAD(object);
169     WebKitDownloadPrivate* priv = download->priv;
170
171     switch(prop_id) {
172     case PROP_NETWORK_REQUEST:
173         priv->networkRequest = WEBKIT_NETWORK_REQUEST(g_value_dup_object(value));
174         // This is safe as network-request is a construct only property and
175         // suggestedFilename is initially null.
176         priv->suggestedFilename = g_path_get_basename(webkit_network_request_get_uri(priv->networkRequest));
177         break;
178     case PROP_DESTINATION_URI:
179         webkit_download_set_destination_uri(download, g_value_get_string(value));
180         break;
181     default:
182         G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec);
183     }
184 }
185
186 static void webkit_download_class_init(WebKitDownloadClass* downloadClass)
187 {
188     GObjectClass* objectClass = G_OBJECT_CLASS(downloadClass);
189     objectClass->dispose = webkit_download_dispose;
190     objectClass->finalize = webkit_download_finalize;
191     objectClass->get_property = webkit_download_get_property;
192     objectClass->set_property = webkit_download_set_property;
193
194     /**
195      * WebKitDownload::error:
196      * @download: the object on which the signal is emitted
197      * @current_bytes: the current count of bytes downloaded
198      * @total_bytes: the total bytes count in the downloaded file, aka file size.
199      *
200      * Indicates an error in the download.
201      *
202      * Since: 1.1.2
203      */
204     webkit_download_signals[ERROR] = g_signal_new("error",
205             G_TYPE_FROM_CLASS(downloadClass),
206             (GSignalFlags)(G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION),
207             0,
208             g_signal_accumulator_true_handled,
209             NULL,
210             webkit_marshal_BOOLEAN__INT_INT_STRING,
211             G_TYPE_BOOLEAN, 3,
212             G_TYPE_INT,
213             G_TYPE_INT,
214             G_TYPE_STRING);
215
216     // Properties.
217
218     /**
219      * WebKitDownload:network-request
220      *
221      * The #WebKitNetworkRequest instance associated with the download.
222      *
223      * Since: 1.1.2
224      */
225     g_object_class_install_property(objectClass,
226                                     PROP_NETWORK_REQUEST,
227                                     g_param_spec_object("network-request",
228                                                         "Network Request",
229                                                         "The network request for the URI that should be downloaded",
230                                                         WEBKIT_TYPE_NETWORK_REQUEST,
231                                                         (GParamFlags)(WEBKIT_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)));
232
233     /**
234      * WebKitDownload:destination-uri
235      *
236      * The URI of the save location for this download.
237      *
238      * Since: 1.1.2
239      */
240     g_object_class_install_property(objectClass,
241                                     PROP_DESTINATION_URI,
242                                     g_param_spec_string("destination-uri",
243                                                         "Destination URI",
244                                                         "The destination URI where to save the file",
245                                                         "",
246                                                         WEBKIT_PARAM_READWRITE));
247
248     /**
249      * WebKitDownload:suggested-filename
250      *
251      * The file name suggested as default when saving
252      *
253      * Since: 1.1.2
254      */
255     g_object_class_install_property(objectClass,
256                                     PROP_SUGGESTED_FILENAME,
257                                     g_param_spec_string("suggested-filename",
258                                                         "Suggested Filename",
259                                                         "The filename suggested as default when saving",
260                                                         "",
261                                                         WEBKIT_PARAM_READABLE));
262
263     /**
264      * WebKitDownload:progress:
265      *
266      * Determines the current progress of the download.
267      *
268      * Since: 1.1.2
269      */
270     g_object_class_install_property(objectClass, PROP_PROGRESS,
271                                     g_param_spec_double("progress",
272                                                         "Progress",
273                                                         "Determines the current progress of the download",
274                                                         0.0, 1.0, 1.0,
275                                                         WEBKIT_PARAM_READABLE));
276
277     /**
278      * WebKitDownload:current-size
279      *
280      * The length of the data already downloaded
281      *
282      * Since: 1.1.2
283      */
284     g_object_class_install_property(objectClass,
285                                     PROP_CURRENT_SIZE,
286                                     g_param_spec_uint64("current-size",
287                                                         "Current Size",
288                                                         "The length of the data already downloaded",
289                                                         0, G_MAXUINT64, 0,
290                                                         WEBKIT_PARAM_READABLE));
291
292     /**
293      * WebKitDownload:total-size
294      *
295      * The total size of the file
296      *
297      * Since: 1.1.2
298      */
299     g_object_class_install_property(objectClass,
300                                     PROP_CURRENT_SIZE,
301                                     g_param_spec_uint64("total-size",
302                                                         "Total Size",
303                                                         "The total size of the file",
304                                                         0, G_MAXUINT64, 0,
305                                                         WEBKIT_PARAM_READABLE));
306
307     g_type_class_add_private(downloadClass, sizeof(WebKitDownloadPrivate));
308 }
309
310 static void webkit_download_init(WebKitDownload* download)
311 {
312     WebKitDownloadPrivate* priv = WEBKIT_DOWNLOAD_GET_PRIVATE(download);
313     download->priv = priv;
314
315     priv->downloadClient = new DownloadClient(download);
316     priv->currentSize = 0;
317     priv->state = WEBKIT_DOWNLOAD_STATE_CREATED;
318 }
319
320 /**
321  * webkit_download_new:
322  * @request: a #WebKitNetworkRequest
323  *
324  * Creates a new #WebKitDownload object for the given
325  * #WebKitNetworkRequest object.
326  *
327  * Returns: the new #WebKitDownload
328  *
329  * Since: 1.1.2
330  */
331 WebKitDownload* webkit_download_new(WebKitNetworkRequest* request)
332 {
333     g_return_val_if_fail(request, NULL);
334
335     return WEBKIT_DOWNLOAD(g_object_new(WEBKIT_TYPE_DOWNLOAD, "network-request", request, NULL));
336 }
337
338 static gboolean webkit_download_open_stream_for_uri(WebKitDownload* download, const gchar* uri, gboolean append=FALSE)
339 {
340     g_return_val_if_fail(uri, FALSE);
341
342     WebKitDownloadPrivate* priv = download->priv;
343     GFile* file = g_file_new_for_uri(uri);
344     GError* error = NULL;
345
346     if (append)
347         priv->outputStream = g_file_append_to(file, G_FILE_CREATE_NONE, NULL, &error);
348     else
349         priv->outputStream = g_file_replace(file, NULL, TRUE, G_FILE_CREATE_NONE, NULL, &error);
350
351     g_object_unref(file);
352
353     if (error) {
354         gboolean handled;
355         g_signal_emit_by_name(download, "error", 0, WEBKIT_DOWNLOAD_ERROR_DESTINATION, error->message, &handled);
356         g_error_free(error);
357         return FALSE;
358     }
359
360     return TRUE;
361 }
362
363 static void webkit_download_close_stream(WebKitDownload* download)
364 {
365     WebKitDownloadPrivate* priv = download->priv;
366     if (priv->outputStream) {
367         g_object_unref(priv->outputStream);
368         priv->outputStream = NULL;
369     }
370 }
371
372 /**
373  * webkit_download_start:
374  * @download: the #WebKitDownload
375  *
376  * Initiates the download. Notice that you must have set the
377  * destination-uri property before calling this method.
378  *
379  * Since: 1.1.2
380  */
381 void webkit_download_start(WebKitDownload* download)
382 {
383     g_return_if_fail(WEBKIT_IS_DOWNLOAD(download));
384
385     WebKitDownloadPrivate* priv = download->priv;
386     g_return_if_fail(priv->destinationURI);
387     g_return_if_fail(priv->state == WEBKIT_DOWNLOAD_STATE_CREATED);
388     g_return_if_fail(priv->timer == NULL);
389
390     if (priv->resourceHandle)
391         priv->resourceHandle->setClient(priv->downloadClient);
392     else {
393         // FIXME: Use the actual request object when WebKitNetworkRequest is finished.
394         ResourceRequest request(webkit_network_request_get_uri(priv->networkRequest));
395         priv->resourceHandle = ResourceHandle::create(request, priv->downloadClient, 0, false, false, false);
396     }
397
398     priv->timer = g_timer_new();
399     webkit_download_open_stream_for_uri(download, priv->destinationURI);
400 }
401
402 /**
403  * webkit_download_cancel:
404  * @download: the #WebKitDownload
405  *
406  * Cancels the download. Calling this will not free the
407  * #WebKitDownload object, so you still need to call
408  * g_object_unref() on it, if you are the owner of a reference. Notice
409  * that cancelling the download provokes the emission of the
410  * WebKitDownload::error signal, reporting that the download was
411  * cancelled.
412  *
413  * Since: 1.1.2
414  */
415 void webkit_download_cancel(WebKitDownload* download)
416 {
417     g_return_if_fail(WEBKIT_IS_DOWNLOAD(download));
418
419     WebKitDownloadPrivate* priv = download->priv;
420
421     // Cancel may be called even if start was not called, so we need
422     // to make sure timer is non-NULL.
423     if (priv->timer)
424         g_timer_stop(priv->timer);
425
426     if (priv->resourceHandle)
427         priv->resourceHandle->cancel();
428
429     priv->state = WEBKIT_DOWNLOAD_STATE_CANCELLED;
430
431     gboolean handled;
432     g_signal_emit_by_name(download, "error", 0, WEBKIT_DOWNLOAD_ERROR_CANCELLED_BY_USER, "User cancelled the download", &handled);
433 }
434
435 /**
436  * webkit_download_get_uri:
437  * @download: the #WebKitDownload
438  *
439  * Convenience method to retrieve the URI from the
440  * #WebKitNetworkRequest which is being downloaded.
441  *
442  * Returns: the uri
443  *
444  * Since: 1.1.2
445  */
446 const gchar* webkit_download_get_uri(WebKitDownload* download)
447 {
448     g_return_val_if_fail(WEBKIT_IS_DOWNLOAD(download), NULL);
449
450     WebKitDownloadPrivate* priv = download->priv;
451     return webkit_network_request_get_uri(priv->networkRequest);
452 }
453
454 /**
455  * webkit_download_get_network_request:
456  * @download: the #WebKitDownload
457  *
458  * Retrieves the #WebKitNetworkRequest object that backs the download
459  * process.
460  *
461  * Returns: the #WebKitNetworkRequest instance
462  *
463  * Since: 1.1.2
464  */
465 WebKitNetworkRequest* webkit_download_get_network_request(WebKitDownload* download)
466 {
467     g_return_val_if_fail(WEBKIT_IS_DOWNLOAD(download), NULL);
468
469     WebKitDownloadPrivate* priv = download->priv;
470     return priv->networkRequest;
471 }
472
473 static void webkit_download_set_response(WebKitDownload* download, const ResourceResponse& response)
474 {
475     // FIXME Use WebKitNetworkResponse when it's merged.
476     WebKitDownloadPrivate* priv = download->priv;
477     priv->networkResponse = new ResourceResponse(response);
478 }
479
480 /**
481  * webkit_download_get_suggested_filename:
482  * @download: the #WebKitDownload
483  *
484  * Retrieves the filename that was suggested by the server, or the one
485  * derived by WebKit from the URI.
486  *
487  * Returns: the suggested filename
488  *
489  * Since: 1.1.2
490  */
491 const gchar* webkit_download_get_suggested_filename(WebKitDownload* download)
492 {
493     g_return_val_if_fail(WEBKIT_IS_DOWNLOAD(download), NULL);
494
495     WebKitDownloadPrivate* priv = download->priv;
496     return priv->suggestedFilename;
497 }
498
499 /**
500  * webkit_download_get_destination_uri:
501  * @download: the #WebKitDownload
502  *
503  * Obtains the URI to which the downloaded file will be written. This
504  * must have been set by the application before calling
505  * webkit_download_start(), and may be %NULL.
506  *
507  * Returns: the destination URI or %NULL
508  *
509  * Since: 1.1.2
510  */
511 const gchar* webkit_download_get_destination_uri(WebKitDownload* download)
512 {
513     g_return_val_if_fail(WEBKIT_IS_DOWNLOAD(download), NULL);
514
515     WebKitDownloadPrivate* priv = download->priv;
516     return priv->destinationURI;
517 }
518
519 /**
520  * webkit_download_set_destination_uri:
521  * @download: the #WebKitDownload
522  * @destination_uri: the destination URI
523  *
524  * Defines the URI that should be used to save the downloaded file to.
525  *
526  * Since: 1.1.2
527  */
528 void webkit_download_set_destination_uri(WebKitDownload* download, const gchar* destination_uri)
529 {
530     g_return_if_fail(WEBKIT_IS_DOWNLOAD(download));
531     g_return_if_fail(destination_uri);
532
533     WebKitDownloadPrivate* priv = download->priv;
534     if (priv->destinationURI && !strcmp(priv->destinationURI, destination_uri))
535         return;
536
537     if (priv->state != WEBKIT_DOWNLOAD_STATE_CREATED && priv->state != WEBKIT_DOWNLOAD_STATE_CANCELLED) {
538         ASSERT(priv->destinationURI);
539
540         gboolean downloading = priv->outputStream != NULL;
541         if (downloading)
542             webkit_download_close_stream(download);
543
544         GFile* src = g_file_new_for_uri(priv->destinationURI);
545         GFile* dest = g_file_new_for_uri(destination_uri);
546         GError* error = NULL;
547
548         g_file_move(src, dest, G_FILE_COPY_BACKUP, NULL, NULL, NULL, &error);
549
550         g_object_unref(src);
551         g_object_unref(dest);
552
553         g_free(priv->destinationURI);
554         priv->destinationURI = g_strdup(destination_uri);
555
556         if (error) {
557             gboolean handled;
558             g_signal_emit_by_name(download, "error", 0, WEBKIT_DOWNLOAD_ERROR_DESTINATION, error->message, &handled);
559             g_error_free(error);
560             return;
561         }
562
563         if (downloading) {
564             if (!webkit_download_open_stream_for_uri(download, destination_uri, TRUE)) {
565                 webkit_download_cancel(download);
566                 return;
567             }
568         }
569     } else {
570         g_free(priv->destinationURI);
571         priv->destinationURI = g_strdup(destination_uri);
572     }
573
574     // Only notify change if everything went fine.
575     g_object_notify(G_OBJECT(download), "destination-uri");
576 }
577
578 /**
579  * webkit_download_get_state:
580  * @download: the #WebKitDownload
581  *
582  * Obtains the current state of the download, as a
583  * #WebKitDownloadState.
584  *
585  * Returns: the current #WebKitDownloadState
586  *
587  * Since: 1.1.2
588  */
589 WebKitDownloadState webkit_download_get_state(WebKitDownload* download)
590 {
591     g_return_val_if_fail(WEBKIT_IS_DOWNLOAD(download), WEBKIT_DOWNLOAD_STATE_ERROR);
592
593     WebKitDownloadPrivate* priv = download->priv;
594     return priv->state;
595 }
596
597 /**
598  * webkit_download_get_total_size:
599  * @download: the #WebKitDownload
600  *
601  * Returns the expected total size of the download. This is expected
602  * because the server may provide incorrect or missing
603  * Content-Length. Notice that this may grow over time, as it will be
604  * always the same as current_size in the cases where current size
605  * surpasses it.
606  *
607  * Returns: the expected total size of the downloaded file
608  *
609  * Since: 1.1.2
610  */
611 guint64 webkit_download_get_total_size(WebKitDownload* download)
612 {
613     g_return_val_if_fail(WEBKIT_IS_DOWNLOAD(download), 0);
614
615     WebKitDownloadPrivate* priv = download->priv;
616     if (!priv->networkResponse)
617         return 0;
618
619     return MAX(priv->currentSize, priv->networkResponse->expectedContentLength());
620 }
621
622 /**
623  * webkit_download_get_current_size:
624  * @download: the #WebKitDownload
625  *
626  * Current already downloaded size.
627  *
628  * Returns: the already downloaded size
629  *
630  * Since: 1.1.2
631  */
632 guint64 webkit_download_get_current_size(WebKitDownload* download)
633 {
634     g_return_val_if_fail(WEBKIT_IS_DOWNLOAD(download), 0);
635
636     WebKitDownloadPrivate* priv = download->priv;
637     return priv->currentSize;
638 }
639
640 /**
641  * webkit_download_get_progress:
642  * @download: a #WebKitDownload
643  *
644  * Determines the current progress of the download.
645  *
646  * Returns: a #gdouble ranging from 0.0 to 1.0.
647  *
648  * Since: 1.1.2
649  */
650 gdouble webkit_download_get_progress(WebKitDownload* download)
651 {
652     g_return_val_if_fail(WEBKIT_IS_DOWNLOAD(download), 1.0);
653
654     WebKitDownloadPrivate* priv = download->priv;
655     gdouble total_size = (gdouble)priv->networkResponse->expectedContentLength();
656
657     if (total_size == 0)
658         return 1.0;
659
660     return ((gdouble)priv->currentSize) / total_size;
661 }
662
663 /**
664  * webkit_download_get_elapsed_time:
665  * @download: a #WebKitDownload
666  *
667  * Elapsed time for the download in seconds, including any fractional
668  * part. If the download is finished, had an error or was cancelled
669  * this is the time between its start and the event.
670  *
671  * Returns: seconds since the download was started, as a #gdouble
672  *
673  * Since: 1.1.2
674  */
675 gdouble webkit_download_get_elapsed_time(WebKitDownload* download)
676 {
677     g_return_val_if_fail(WEBKIT_IS_DOWNLOAD(download), 0.0);
678
679     WebKitDownloadPrivate* priv = download->priv;
680     return g_timer_elapsed(priv->timer, NULL);
681 }
682
683 static void webkit_download_received_data(WebKitDownload* download, const gchar* data, int length)
684 {
685     WebKitDownloadPrivate* priv = download->priv;
686
687     if (priv->currentSize == 0)
688         priv->state = WEBKIT_DOWNLOAD_STATE_STARTED;
689
690     ASSERT(priv->outputStream);
691
692     gsize bytes_written;
693     GError* error = NULL;
694
695     g_output_stream_write_all(G_OUTPUT_STREAM(priv->outputStream),
696                               data, length, &bytes_written, NULL, &error);
697
698     if (error) {
699         gboolean handled;
700         g_signal_emit_by_name(download, "error", 0, WEBKIT_DOWNLOAD_ERROR_DESTINATION, error->message, &handled);
701         g_error_free(error);
702         return;
703     }
704
705     priv->currentSize += length;
706     g_object_notify(G_OBJECT(download), "current-size");
707
708     ASSERT(priv->networkResponse);
709     if (priv->currentSize > priv->networkResponse->expectedContentLength())
710         g_object_notify(G_OBJECT(download), "total-size");
711
712     // FIXME: Throttle the number of updates? Should we remove the
713     // previous g_object_notify()s if we are going to throttle the
714     // progress updates?
715     g_object_notify(G_OBJECT(download), "progress");
716 }
717
718 static void webkit_download_finished_loading(WebKitDownload* download)
719 {
720     webkit_download_close_stream(download);
721
722     WebKitDownloadPrivate* priv = download->priv;
723
724     g_timer_stop(priv->timer);
725     priv->state = WEBKIT_DOWNLOAD_STATE_FINISHED;
726
727     g_object_notify(G_OBJECT(download), "progress");
728 }
729
730 static void webkit_download_error(WebKitDownload* download, const ResourceError& error)
731 {
732     webkit_download_close_stream(download);
733
734     WebKitDownloadPrivate* priv = download->priv;
735
736     g_timer_stop(priv->timer);
737     priv->state = WEBKIT_DOWNLOAD_STATE_ERROR;
738
739     gboolean handled;
740     g_signal_emit_by_name(download, "error", 0, WEBKIT_DOWNLOAD_ERROR_NETWORK, error.localizedDescription().utf8().data(), &handled);
741 }
742
743 DownloadClient::DownloadClient(WebKitDownload* download)
744     : m_download(download)
745 {
746 }
747
748 void DownloadClient::didReceiveResponse(ResourceHandle*, const ResourceResponse& response)
749 {
750     webkit_download_set_response(m_download, response);
751 }
752
753 void DownloadClient::didReceiveData(ResourceHandle*, const char* data, int length, int lengthReceived)
754 {
755     webkit_download_received_data(m_download, data, length);
756 }
757
758 void DownloadClient::didFinishLoading(ResourceHandle*)
759 {
760     webkit_download_finished_loading(m_download);
761 }
762
763 void DownloadClient::didFail(ResourceHandle*, const ResourceError& error)
764 {
765     webkit_download_error(m_download, error);
766 }
767
768 void DownloadClient::wasBlocked(ResourceHandle*)
769 {
770     // FIXME: Implement this when we have the new frame loader signals
771     // and error handling.
772     notImplemented();
773 }
774
775 void DownloadClient::cannotShowURL(ResourceHandle*)
776 {
777     // FIXME: Implement this when we have the new frame loader signals
778     // and error handling.
779     notImplemented();
780 }
781
782 }