2009-11-08 Chris Toshok <toshok@ximian.com>
[moon.git] / src / downloader.cpp
blob7f5dc77274aae2e86c4f99d349f542d1fd2d3290
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
2 /*
3 * downloader.cpp: Downloader class.
5 * The downloader implements two modes of operation:
7 * bare bones: this is the interface expected by Javascript and C#
8 * this is the default if the caller does not call
9 * Downloader::SetWriteFunc
11 * progressive: this interface is used internally by the Image
12 * class to do progressive loading. If you want to
13 * use this mode, you must call the SetWriteFunc routine
14 * to install your callbacks before starting the download.
16 * TODO:
17 * Need a mechanism to notify the managed client of errors during
18 * download.
20 * Need to provide the buffer we downloaded to GetResponseText(string PartName)
21 * so we can return the response text for the given part name.
23 * The providers should store the files *somewhere* and should be able
24 * to respond to the "GetResponsetext" above on demand. The current
25 * code in demo.cpp and ManagedDownloader are not complete in this regard as
26 * they only stream
28 * Contact:
29 * Moonlight List (moonlight-list@lists.ximian.com)
31 * Copyright 2007 Novell, Inc. (http://www.novell.com)
33 * See the LICENSE file included with the distribution for details.
38 #include <config.h>
40 #include <sys/types.h>
41 #include <sys/stat.h>
42 #include <unistd.h>
43 #include <fcntl.h>
45 #include "downloader.h"
46 #include "file-downloader.h"
47 #include "mms-downloader.h"
48 #include "runtime.h"
49 #include "utils.h"
50 #include "error.h"
51 #include "debug.h"
52 #include "uri.h"
53 #include "deployment.h"
56 // Downloader
59 Downloader::Downloader ()
60 : DependencyObject (Type::DOWNLOADER)
62 LOG_DOWNLOADER ("Downloader::Downloader ()\n");
64 downloader_state = Downloader::create_state (this);
65 user_data = NULL;
66 context = NULL;
67 notify_size = NULL;
68 writer = NULL;
69 internal_dl = NULL;
71 send_queued = false;
72 started = false;
73 aborted = false;
74 completed = false;
75 custom_header_support = false;
76 disable_cache = false;
77 file_size = -2;
78 total = 0;
80 filename = NULL;
81 buffer = NULL;
82 failed_msg = NULL;
86 Downloader::~Downloader ()
88 LOG_DOWNLOADER ("Downloader::~Downloader ()\n");
90 Downloader::destroy_state (downloader_state);
92 g_free (filename);
93 g_free (buffer);
94 g_free (failed_msg);
96 // NOTE:
97 // mms code relies on the internal downloader to be alive while it has a ref on the downloader
98 // update mms code if this assumption changes.
99 if (internal_dl != NULL)
100 internal_dl->unref ();
103 void
104 Downloader::InternalAbort ()
106 LOG_DOWNLOADER ("Downloader::InternalAbort ()\n");
107 if (!GetSurface ())
108 return;
110 abort_func (downloader_state);
113 void
114 Downloader::Abort ()
116 LOG_DOWNLOADER ("Downloader::Abort ()\n");
118 SetCurrentDeployment ();
120 if (!aborted && !failed_msg) {
121 InternalAbort ();
122 SetDownloadProgress (0.0);
123 send_queued = false;
124 aborted = true;
128 char *
129 Downloader::GetDownloadedFilename (const char *partname)
131 LOG_DOWNLOADER ("Downloader::GetDownloadedFilename (%s)\n", filename);
133 g_return_val_if_fail (internal_dl != NULL && internal_dl->Is (Type::FILEDOWNLOADER), NULL);
135 // This is a horrible hack to work around mozilla bug #444160
136 // Basically if a very small file is downloaded (<64KB in mozilla as of Jan5/09
137 // it can be inserted into a shared cache map, and served up to us without ever
138 // giving us the filename for a NP_ASFILE request.
139 if (buffer != NULL) {
140 FileDownloader *fdl = (FileDownloader *) internal_dl;
141 char *tmpfile;
142 int fd;
144 tmpfile = g_build_filename (g_get_tmp_dir (), "mozilla-workaround-XXXXXX", NULL);
145 if ((fd = g_mkstemp (tmpfile)) == -1) {
146 g_free (tmpfile);
147 return NULL;
150 if (write_all (fd, buffer, (size_t) total) == -1) {
151 unlink (tmpfile);
152 g_free (tmpfile);
153 close (fd);
154 return NULL;
157 close (fd);
159 fdl->SetFilename (tmpfile);
160 fdl->SetUnlink (true);
161 g_free (tmpfile);
162 g_free (buffer);
163 buffer = NULL;
166 return internal_dl->GetDownloadedFilename (partname);
169 char *
170 Downloader::GetResponseText (const char *PartName, gint64 *size)
172 LOG_DOWNLOADER ("Downloader::GetResponseText (%s, %p)\n", PartName, size);
174 // This is a horrible hack to work around mozilla bug #444160
175 // Basically if a very small file is downloaded (<64KB in mozilla as of Jan5/09
176 // it can be inserted into a shared cache map, and served up to us without ever
177 // giving us the filename for a NP_ASFILE request.
178 if (PartName == NULL && buffer != NULL) {
179 char *data;
180 char b[4096];
181 ssize_t nread;
182 GByteArray *buf;
184 TextStream *stream = new TextStream ();
186 if (!stream->OpenBuffer (buffer, total)) {
187 delete stream;
188 return NULL;
191 buf = g_byte_array_new ();
192 while ((nread = stream->Read (b, sizeof (b))) > 0)
193 g_byte_array_append (buf, (const guint8 *) b, nread);
195 *size = buf->len;
197 g_byte_array_append (buf, (const guint8 *) "", 1);
198 data = (char *) buf->data;
200 g_byte_array_free (buf, false);
201 delete stream;
203 return data;
206 return internal_dl->GetResponseText (PartName, size);
209 void
210 Downloader::InternalOpen (const char *verb, const char *uri)
212 LOG_DOWNLOADER ("Downloader::InternalOpen (%s, %s) requires custom header support: %i\n", verb, uri, custom_header_support);
214 open_func (downloader_state, verb, uri, custom_header_support, disable_cache);
217 static bool
218 same_scheme (const Uri *uri1, const Uri *uri2)
220 return uri1->GetScheme () && uri2->GetScheme () &&
221 !strcmp (uri1->GetScheme (), uri2->GetScheme ());
224 static bool
225 same_domain (const Uri *uri1, const Uri *uri2)
227 const char *host1 = uri1->GetHost ();
228 const char *host2 = uri2->GetHost ();
230 if (host1 && host2)
231 return g_ascii_strcasecmp (host1, host2) == 0;
233 if (!host1 && !host2)
234 return true;
236 return false;
239 // Reference: URL Access Restrictions in Silverlight 2
240 // http://msdn.microsoft.com/en-us/library/cc189008(VS.95).aspx
241 bool
242 Downloader::CheckRedirectionPolicy (const char *url)
244 if (!url)
245 return false;
247 // the original URI
248 Uri *source = GetUri ();
249 if (Uri::IsNullOrEmpty (source))
250 return false;
252 // if the (original) source is relative then the (final) 'url' will be the absolute version of the uri
253 // or if the source scheme is "file" then no server is present for redirecting the url somewhere else
254 if (!source->IsAbsolute () || source->IsScheme ("file"))
255 return true;
257 char *strsrc = source->ToString ();
258 // if the original URI and the end URI are identical then there was no redirection involved
259 bool retval = (g_ascii_strcasecmp (strsrc, url) == 0);
260 g_free (strsrc);
261 if (retval)
262 return true;
264 // the destination URI
265 Uri *dest = new Uri ();
266 if (dest->Parse (url)) {
267 // there was a redirection, but is it allowed ?
268 switch (access_policy) {
269 case DownloaderPolicy:
270 // Redirection allowed for 'same domain' and 'same scheme'
271 // note: if 'dest' is relative then it's the same scheme and site
272 if (!dest->IsAbsolute () || (same_domain (source, dest) && same_scheme (source, dest)))
273 retval = true;
274 break;
275 case MediaPolicy:
276 // Redirection allowed for: 'same scheme' and 'same or different sites'
277 // note: if 'dest' is relative then it's the same scheme and site
278 if (!dest->IsAbsolute () || same_scheme (source, dest))
279 retval = true;
280 break;
281 case XamlPolicy:
282 case FontPolicy:
283 case MsiPolicy:
284 case StreamingPolicy:
285 // Redirection NOT allowed
286 break;
287 default:
288 // no policy (e.g. downloading codec EULA and binary) is allowed
289 retval = true;
290 break;
294 delete dest;
296 return retval;
299 // Reference: URL Access Restrictions in Silverlight 2
300 // http://msdn.microsoft.com/en-us/library/cc189008(VS.95).aspx
301 static bool
302 validate_policy (const char *location, const Uri *source, DownloaderAccessPolicy policy)
304 if (!location || !source)
305 return true;
307 if (!source->IsAbsolute ()) {
308 //relative uri, not checking policy
309 return true;
312 Uri *target = new Uri ();
313 if (!target->Parse (location)) {
314 delete target;
315 return false;
318 bool retval = true;
319 switch (policy) {
320 case DownloaderPolicy:
321 //Allowed schemes: http, https
322 if (!target->IsScheme ("http") && !target->IsScheme ("https"))
323 retval = false;
324 //X-Scheme: no
325 if (!same_scheme (target, source))
326 retval = false;
327 //X-Domain: requires policy file
328 // FIXME only managed is implemented
329 if (!same_domain (target, source))
330 retval = false;
331 break;
332 case MsiPolicy:
333 case MediaPolicy: //Media, images, ASX
334 //Allowed schemes: http, https, file
335 if (!target->IsScheme ("http") && !target->IsScheme ("https") && !target->IsScheme ("file"))
336 retval = false;
337 //X-Scheme: no
338 if (!same_scheme (target, source))
339 retval = false;
340 //X-Domain: Allowed
341 break;
342 case XamlPolicy:
343 //Allowed schemes: http, https, file
344 if (!target->IsScheme ("http") && !target->IsScheme ("https") && !target->IsScheme ("file"))
345 retval = false;
346 //X-Scheme: no
347 if (!same_scheme (target, source))
348 retval =false;
349 //X-domain: allowed if not HTTPS to HTTPS
350 if (!same_domain (target, source) && target->IsScheme ("https") && source->IsScheme ("https"))
351 retval = false;
352 break;
353 case FontPolicy:
354 //Allowed schemes: http, https, file
355 if (!target->IsScheme ("http") && !target->IsScheme ("https") && !target->IsScheme ("file"))
356 retval = false;
357 //X-Scheme: no
358 if (!same_scheme (target, source))
359 retval = false;
360 //X-domain: no
361 if (!same_domain (target, source))
362 retval = false;
363 break;
364 case StreamingPolicy: //Streaming media
365 //Allowed schemes: http
366 if (!target->IsScheme ("http"))
367 retval = false;
368 //X-scheme: Not from https
369 if (source->IsScheme ("https") && !same_scheme (source, target))
370 retval = false;
371 //X-domain: allowed if not HTTPS to HTTPS
372 if (!same_domain (target, source) && target->IsScheme ("https") && source->IsScheme ("https"))
373 retval = false;
374 break;
375 default:
376 break;
379 delete target;
381 return retval;
384 void
385 Downloader::OpenInitialize ()
387 send_queued = false;
388 started = false;
389 aborted = false;
390 completed = false;
391 file_size = -2;
392 total = 0;
394 g_free (failed_msg);
395 g_free (filename);
396 g_free (buffer);
397 failed_msg = NULL;
398 filename = NULL;
399 buffer = NULL;
402 void
403 Downloader::Open (const char *verb, const char *uri, DownloaderAccessPolicy policy)
405 LOG_DOWNLOADER ("Downloader::Open (%s, %s)\n", verb, uri);
407 OpenInitialize ();
409 Uri *url = new Uri ();
410 if (url->Parse (uri))
411 Open (verb, url, policy);
413 delete url;
416 bool
417 Downloader::ValidateDownloadPolicy (const char *source_location, Uri *uri, DownloaderAccessPolicy policy)
419 Uri *src_uri = NULL;
420 bool valid;
422 if (!uri->isAbsolute && source_location) {
423 src_uri = new Uri ();
424 if (!src_uri->Parse (source_location)) {
425 delete src_uri;
426 return false;
429 src_uri->Combine (uri);
430 uri = src_uri;
433 valid = validate_policy (source_location, uri, policy);
434 delete src_uri;
436 return valid;
439 void
440 Downloader::Open (const char *verb, Uri *uri, DownloaderAccessPolicy policy)
442 const char *source_location;
443 Uri *src_uri = NULL;
444 Uri *url = uri;
445 char *str;
447 LOG_DOWNLOADER ("Downloader::Open (%s, %p)\n", verb, uri);
449 OpenInitialize ();
451 access_policy = policy;
453 if (!(source_location = GetDeployment ()->GetXapLocation ()))
454 source_location = GetSurface ()->GetSourceLocation ();
456 // FIXME: ONLY VALIDATE IF USED FROM THE PLUGIN
457 if (!Downloader::ValidateDownloadPolicy (source_location, uri, policy)) {
458 LOG_DOWNLOADER ("aborting due to security policy violation\n");
459 failed_msg = g_strdup ("Security Policy Violation");
460 Abort ();
461 return;
464 if (!uri->isAbsolute && source_location) {
465 src_uri = new Uri ();
466 if (!src_uri->Parse (source_location)) {
467 delete src_uri;
468 return;
471 src_uri->Combine (uri);
472 url = src_uri;
475 if (policy == StreamingPolicy) {
476 internal_dl = (InternalDownloader *) new MmsDownloader (this);
477 } else {
478 internal_dl = (InternalDownloader *) new FileDownloader (this);
481 send_queued = false;
483 SetUri (uri);
485 str = url->ToString ();
486 delete src_uri;
488 internal_dl->Open (verb, str);
489 g_free (str);
492 void
493 Downloader::InternalSetHeader (const char *header, const char *value)
495 LOG_DOWNLOADER ("Downloader::InternalSetHeader (%s, %s)\n", header, value);
497 header_func (downloader_state, header, value);
500 void
501 Downloader::InternalSetHeaderFormatted (const char *header, char *value)
503 InternalSetHeader (header, (const char *) value);
504 g_free (value);
507 void
508 Downloader::InternalSetBody (void *body, guint32 length)
510 LOG_DOWNLOADER ("Downloader::InternalSetBody (%p, %u)\n", body, length);
512 body_func (downloader_state, body, length);
515 void
516 Downloader::SendInternal ()
518 LOG_DOWNLOADER ("Downloader::SendInternal ()\n");
520 if (!GetSurface ()) {
521 // The plugin is already checking for surface before calling Send, so
522 // if we get here, it's either managed code doing something wrong or ourselves.
523 g_warning ("Downloader::SendInternal (): No surface!\n");
526 if (!send_queued)
527 return;
529 send_queued = false;
531 if (completed) {
532 // Consumer is re-sending a request which finished successfully.
533 NotifyFinished (NULL);
534 return;
537 if (failed_msg != NULL) {
538 // Consumer is re-sending a request which failed.
539 Emit (DownloadFailedEvent, new ErrorEventArgs (DownloadError,
540 MoonError (MoonError::EXCEPTION, 1, failed_msg)));
541 return;
544 started = true;
545 aborted = false;
547 send_func (downloader_state);
550 static void
551 send_async (EventObject *user_data)
553 Downloader *downloader = (Downloader *) user_data;
555 downloader->SendInternal ();
558 void
559 Downloader::Send ()
561 LOG_DOWNLOADER ("Downloader::Send ()\n");
563 if (!GetSurface ()) {
564 // The plugin is already checking for surface before calling Send, so
565 // if we get here, it's either managed code doing something wrong or ourselves.
566 g_warning ("Downloader::Send (): No surface!\n");
569 if (send_queued)
570 return;
572 send_queued = true;
573 SetStatusText ("");
574 SetStatus (0);
576 AddTickCall (send_async);
579 void
580 Downloader::SendNow ()
582 LOG_DOWNLOADER ("Downloader::SendNow ()\n");
584 send_queued = true;
585 SetStatusText ("");
586 SetStatus (0);
588 SendInternal ();
592 // A zero write means that we are done
594 void
595 Downloader::Write (void *buf, gint32 offset, gint32 n)
597 char* struri = NULL;
598 LOG_DOWNLOADER ("Downloader::Write (%p, %i, %i). Uri: %s\n", buf, offset, n, (struri = GetUri ()->ToString ()));
599 g_free (struri);
601 SetCurrentDeployment ();
603 if (aborted)
604 return;
606 if (!GetSurface ())
607 return;
609 internal_dl->Write (buf, offset, n);
612 void
613 Downloader::InternalWrite (void *buf, gint32 offset, gint32 n)
615 LOG_DOWNLOADER ("Downloader::InternalWrite (%p, %i, %i)\n", buf, offset, n);
617 double progress;
619 // Update progress
620 if (n > 0)
621 total += n;
623 if (file_size >= 0) {
624 if ((progress = total / (double) file_size) > 1.0)
625 progress = 1.0;
626 } else
627 progress = 0.0;
629 SetDownloadProgress (progress);
631 Emit (DownloadProgressChangedEvent);
633 if (writer)
634 writer (buf, offset, n, user_data);
636 // This is a horrible hack to work around mozilla bug #444160
637 // See Downloader::GetResponseText for an explanation
638 if (internal_dl->GetObjectType () == Type::FILEDOWNLOADER && n == total && total < 65536) {
639 buffer = (char *) g_malloc ((size_t) total);
640 memcpy (buffer, buf, (size_t) total);
644 void
645 Downloader::SetFilename (const char *fname)
647 LOG_DOWNLOADER ("Downloader::SetFilename (%s)\n", fname);
649 g_free (filename);
650 g_free (buffer);
651 buffer = NULL;
653 filename = g_strdup (fname);
655 internal_dl->SetFilename (filename);
658 void
659 Downloader::NotifyFinished (const char *final_uri)
661 if (aborted)
662 return;
664 SetCurrentDeployment ();
666 if (!GetSurface ())
667 return;
669 SetDownloadProgress (1.0);
671 Emit (DownloadProgressChangedEvent);
673 // HACK, we should provide the actual status text and code
674 SetStatusText ("OK");
675 SetStatus (200);
677 completed = true;
679 Emit (CompletedEvent, NULL);
682 void
683 Downloader::NotifyFailed (const char *msg)
685 LOG_DOWNLOADER ("Downloader::NotifyFailed (%s)\n", msg);
687 /* if we've already been notified of failure, no-op */
688 if (failed_msg)
689 return;
691 SetCurrentDeployment ();
693 if (!GetSurface ())
694 return;
696 // SetStatus (400);
697 // For some reason the status is 0, not updated on errors?
699 Emit (DownloadFailedEvent, new ErrorEventArgs (DownloadError,
700 MoonError (MoonError::EXCEPTION, 1, msg)));
702 failed_msg = g_strdup (msg);
705 void
706 Downloader::NotifySize (gint64 size)
708 LOG_DOWNLOADER ("Downloader::NotifySize (%" G_GINT64_FORMAT ")\n", size);
710 file_size = size;
712 if (aborted)
713 return;
715 SetCurrentDeployment ();
717 if (!GetSurface ())
718 return;
720 if (notify_size)
721 notify_size (size, user_data);
724 bool
725 Downloader::Started ()
727 LOG_DOWNLOADER ("Downloader::Started (): %i\n", started);
729 return started;
732 bool
733 Downloader::Completed ()
735 LOG_DOWNLOADER ("Downloader::Completed (), filename: %s\n", filename);
737 return completed;
740 void
741 Downloader::SetStreamFunctions (DownloaderWriteFunc writer,
742 DownloaderNotifySizeFunc notify_size,
743 gpointer user_data)
745 LOG_DOWNLOADER ("Downloader::SetStreamFunctions\n");
747 this->notify_size = notify_size;
748 this->writer = writer;
749 this->user_data = user_data;
752 void
753 Downloader::SetFunctions (DownloaderCreateStateFunc create_state,
754 DownloaderDestroyStateFunc destroy_state,
755 DownloaderOpenFunc open,
756 DownloaderSendFunc send,
757 DownloaderAbortFunc abort,
758 DownloaderHeaderFunc header,
759 DownloaderBodyFunc body,
760 DownloaderCreateWebRequestFunc request,
761 DownloaderSetResponseHeaderCallbackFunc response_header_callback,
762 DownloaderGetResponseFunc get_response)
764 LOG_DOWNLOADER ("Downloader::SetFunctions\n");
765 Downloader::create_state = create_state;
766 Downloader::destroy_state = destroy_state;
767 Downloader::open_func = open;
768 Downloader::send_func = send;
769 Downloader::abort_func = abort;
770 Downloader::header_func = header;
771 Downloader::body_func = body;
772 Downloader::request_func = request;
773 Downloader::set_response_header_callback_func = response_header_callback;
774 Downloader::get_response_func = get_response;
779 * DownloaderRequest / DownloaderResponse
782 DownloaderResponse::~DownloaderResponse ()
784 if (request != NULL && request->GetDownloaderResponse () == this)
785 request->SetDownloaderResponse (NULL);
786 GetDeployment ()->UnregisterDownloader (this);
789 DownloaderResponse::DownloaderResponse ()
791 aborted = false;
792 started = NULL;
793 available = NULL;
794 finished = NULL;
795 context = NULL;
796 request = NULL;
797 SetDeployment (Deployment::GetCurrent ());
798 GetDeployment ()->RegisterDownloader (this);
801 DownloaderResponse::DownloaderResponse (DownloaderResponseStartedHandler started, DownloaderResponseDataAvailableHandler available, DownloaderResponseFinishedHandler finished, gpointer context)
803 this->aborted = false;
804 this->started = started;
805 this->available = available;
806 this->finished = finished;
807 this->context = context;
808 this->request = NULL;
809 SetDeployment (Deployment::GetCurrent ());
810 GetDeployment ()->RegisterDownloader (this);
813 DownloaderRequest::DownloaderRequest (const char *method, const char *uri)
815 this->method = g_strdup (method);
816 this->uri = g_strdup (uri);
817 this->response = NULL;
818 SetDeployment (Deployment::GetCurrent ());
819 GetDeployment ()->RegisterDownloader (this);
822 DownloaderRequest::~DownloaderRequest ()
824 g_free (method);
825 g_free (uri);
826 if (response != NULL && response->GetDownloaderRequest () == this)
827 response->SetDownloaderRequest (NULL);
828 GetDeployment ()->UnregisterDownloader (this);
831 void *
832 Downloader::CreateWebRequest (const char *method, const char *uri)
834 return GetRequestFunc () (method, uri, GetContext ());
837 void
838 Downloader::SetResponseHeaderCallback (DownloaderResponseHeaderCallback callback, gpointer context)
840 if (set_response_header_callback_func != NULL)
841 set_response_header_callback_func (downloader_state, callback, context);
844 DownloaderResponse *
845 Downloader::GetResponse ()
847 if (get_response_func != NULL)
848 return get_response_func (downloader_state);
849 return NULL;
852 void
853 downloader_write (Downloader *dl, void *buf, gint32 offset, gint32 n)
855 dl->Write (buf, offset, n);
858 void
859 downloader_notify_finished (Downloader *dl, const char *fname)
861 dl->SetFilename (fname);
862 dl->NotifyFinished (NULL);
865 void
866 downloader_notify_error (Downloader *dl, const char *msg)
868 dl->NotifyFailed (msg);
871 void
872 downloader_notify_size (Downloader *dl, gint64 size)
874 dl->NotifySize (size);
878 static gpointer
879 dummy_downloader_create_state (Downloader* dl)
881 g_warning ("downloader_set_function has never been called.\n");
882 return NULL;
885 static void
886 dummy_downloader_destroy_state (gpointer state)
888 g_warning ("downloader_set_function has never been called.\n");
891 static void
892 dummy_downloader_open (gpointer state, const char *verb, const char *uri, bool custom_header_support, bool disble_cache)
894 g_warning ("downloader_set_function has never been called.\n");
897 static void
898 dummy_downloader_send (gpointer state)
900 g_warning ("downloader_set_function has never been called.\n");
903 static void
904 dummy_downloader_abort (gpointer state)
906 g_warning ("downloader_set_function has never been called.\n");
909 static void
910 dummy_downloader_header (gpointer state, const char *header, const char *value)
912 g_warning ("downloader_set_function has never been called.\n");
915 static void
916 dummy_downloader_body (gpointer state, void *body, guint32 length)
918 g_warning ("downloader_set_function has never been called.\n");
921 static gpointer
922 dummy_downloader_create_web_request (const char *method, const char *uri, gpointer context)
924 g_warning ("downloader_set_function has never been called.\n");
925 return NULL;
928 static void
929 dummy_downloader_set_response_header_callback (gpointer state, DownloaderResponseHeaderCallback callback, gpointer context)
931 g_warning ("downloader_set_function has never been called.\n");
934 static DownloaderResponse *
935 dummy_downloader_get_response (gpointer state)
937 g_warning ("downloader_set_function has never been called.\n");
938 return NULL;
941 DownloaderCreateStateFunc Downloader::create_state = dummy_downloader_create_state;
942 DownloaderDestroyStateFunc Downloader::destroy_state = dummy_downloader_destroy_state;
943 DownloaderOpenFunc Downloader::open_func = dummy_downloader_open;
944 DownloaderSendFunc Downloader::send_func = dummy_downloader_send;
945 DownloaderAbortFunc Downloader::abort_func = dummy_downloader_abort;
946 DownloaderHeaderFunc Downloader::header_func = dummy_downloader_header;
947 DownloaderBodyFunc Downloader::body_func = dummy_downloader_body;
948 DownloaderCreateWebRequestFunc Downloader::request_func = dummy_downloader_create_web_request;
949 DownloaderSetResponseHeaderCallbackFunc Downloader::set_response_header_callback_func = dummy_downloader_set_response_header_callback;
950 DownloaderGetResponseFunc Downloader::get_response_func = dummy_downloader_get_response;
952 void
953 downloader_init (void)