just kick off another build
[moon.git] / src / downloader.cpp
blobcc95f225bb71bb1670f95a90a5a85e3f60f5ec24
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"
55 // Downloader
58 Downloader::Downloader ()
59 : DependencyObject (Type::DOWNLOADER)
61 LOG_DOWNLOADER ("Downloader::Downloader ()\n");
63 downloader_state = Downloader::create_state (this);
64 user_data = NULL;
65 context = NULL;
66 notify_size = NULL;
67 writer = NULL;
68 internal_dl = NULL;
70 send_queued = false;
71 started = false;
72 aborted = false;
73 completed = false;
74 custom_header_support = false;
75 disable_cache = false;
76 file_size = -2;
77 total = 0;
79 filename = NULL;
80 buffer = NULL;
81 failed_msg = NULL;
85 Downloader::~Downloader ()
87 LOG_DOWNLOADER ("Downloader::~Downloader ()\n");
89 Downloader::destroy_state (downloader_state);
91 g_free (filename);
92 g_free (buffer);
93 g_free (failed_msg);
95 // NOTE:
96 // mms code relies on the internal downloader to be alive while it has a ref on the downloader
97 // update mms code if this assumption changes.
98 if (internal_dl != NULL)
99 internal_dl->unref ();
102 void
103 Downloader::InternalAbort ()
105 LOG_DOWNLOADER ("Downloader::InternalAbort ()\n");
106 if (!GetSurface ())
107 return;
109 abort_func (downloader_state);
112 void
113 Downloader::Abort ()
115 LOG_DOWNLOADER ("Downloader::Abort ()\n");
117 SetCurrentDeployment ();
119 if (!aborted && !failed_msg) {
120 InternalAbort ();
121 SetDownloadProgress (0.0);
122 send_queued = false;
123 aborted = true;
127 char *
128 Downloader::GetDownloadedFilename (const char *partname)
130 LOG_DOWNLOADER ("Downloader::GetDownloadedFilename (%s)\n", filename);
132 g_return_val_if_fail (internal_dl != NULL && internal_dl->Is (Type::FILEDOWNLOADER), NULL);
134 // This is a horrible hack to work around mozilla bug #444160
135 // Basically if a very small file is downloaded (<64KB in mozilla as of Jan5/09
136 // it can be inserted into a shared cache map, and served up to us without ever
137 // giving us the filename for a NP_ASFILE request.
138 if (buffer != NULL) {
139 FileDownloader *fdl = (FileDownloader *) internal_dl;
140 char *tmpfile;
141 int fd;
143 tmpfile = g_build_filename (g_get_tmp_dir (), "mozilla-workaround-XXXXXX", NULL);
144 if ((fd = g_mkstemp (tmpfile)) == -1) {
145 g_free (tmpfile);
146 return NULL;
149 if (write_all (fd, buffer, (size_t) total) == -1) {
150 unlink (tmpfile);
151 g_free (tmpfile);
152 close (fd);
153 return NULL;
156 close (fd);
158 fdl->SetFilename (tmpfile);
159 fdl->SetUnlink (true);
160 g_free (tmpfile);
161 g_free (buffer);
162 buffer = NULL;
165 return internal_dl->GetDownloadedFilename (partname);
168 char *
169 Downloader::GetResponseText (const char *PartName, gint64 *size)
171 LOG_DOWNLOADER ("Downloader::GetResponseText (%s, %p)\n", PartName, size);
173 // This is a horrible hack to work around mozilla bug #444160
174 // Basically if a very small file is downloaded (<64KB in mozilla as of Jan5/09
175 // it can be inserted into a shared cache map, and served up to us without ever
176 // giving us the filename for a NP_ASFILE request.
177 if (PartName == NULL && buffer != NULL) {
178 char *data;
179 char b[4096];
180 ssize_t nread;
181 GByteArray *buf;
183 TextStream *stream = new TextStream ();
185 if (!stream->OpenBuffer (buffer, total)) {
186 delete stream;
187 return NULL;
190 buf = g_byte_array_new ();
191 while ((nread = stream->Read (b, sizeof (b))) > 0)
192 g_byte_array_append (buf, (const guint8 *) b, nread);
194 *size = buf->len;
196 g_byte_array_append (buf, (const guint8 *) "", 1);
197 data = (char *) buf->data;
199 g_byte_array_free (buf, false);
200 delete stream;
202 return data;
205 return internal_dl->GetResponseText (PartName, size);
208 void
209 Downloader::InternalOpen (const char *verb, const char *uri)
211 LOG_DOWNLOADER ("Downloader::InternalOpen (%s, %s) requires custom header support: %i\n", verb, uri, custom_header_support);
213 open_func (downloader_state, verb, uri, custom_header_support, disable_cache);
216 static bool
217 same_scheme (const Uri *uri1, const Uri *uri2)
219 return uri1->GetScheme () && uri2->GetScheme () &&
220 !strcmp (uri1->GetScheme (), uri2->GetScheme ());
223 static bool
224 same_domain (const Uri *uri1, const Uri *uri2)
226 const char *host1 = uri1->GetHost ();
227 const char *host2 = uri2->GetHost ();
229 if (host1 && host2)
230 return g_ascii_strcasecmp (host1, host2) == 0;
232 if (!host1 && !host2)
233 return true;
235 return false;
238 // Reference: URL Access Restrictions in Silverlight 2
239 // http://msdn.microsoft.com/en-us/library/cc189008(VS.95).aspx
240 bool
241 Downloader::CheckRedirectionPolicy (const char *url)
243 if (!url)
244 return false;
246 // the original URI
247 Uri *source = GetUri ();
248 if (Uri::IsNullOrEmpty (source))
249 return false;
251 // if the (original) source is relative then the (final) 'url' will be the absolute version of the uri
252 // or if the source scheme is "file" then no server is present for redirecting the url somewhere else
253 if (!source->IsAbsolute () || source->IsScheme ("file"))
254 return true;
256 char *strsrc = source->ToString ();
257 // if the original URI and the end URI are identical then there was no redirection involved
258 bool retval = (g_ascii_strcasecmp (strsrc, url) == 0);
259 g_free (strsrc);
260 if (retval)
261 return true;
263 // the destination URI
264 Uri *dest = new Uri ();
265 if (dest->Parse (url)) {
266 // there was a redirection, but is it allowed ?
267 switch (access_policy) {
268 case DownloaderPolicy:
269 // Redirection allowed for 'same domain' and 'same scheme'
270 // note: if 'dest' is relative then it's the same scheme and site
271 if (!dest->IsAbsolute () || (same_domain (source, dest) && same_scheme (source, dest)))
272 retval = true;
273 break;
274 case MediaPolicy:
275 // Redirection allowed for: 'same scheme' and 'same or different sites'
276 // note: if 'dest' is relative then it's the same scheme and site
277 if (!dest->IsAbsolute () || same_scheme (source, dest))
278 retval = true;
279 break;
280 case XamlPolicy:
281 case FontPolicy:
282 case MsiPolicy:
283 case StreamingPolicy:
284 // Redirection NOT allowed
285 break;
286 default:
287 // no policy (e.g. downloading codec EULA and binary) is allowed
288 retval = true;
289 break;
293 delete dest;
295 return retval;
298 // Reference: URL Access Restrictions in Silverlight 2
299 // http://msdn.microsoft.com/en-us/library/cc189008(VS.95).aspx
300 static bool
301 validate_policy (const char *location, const Uri *source, DownloaderAccessPolicy policy)
303 if (!location || !source)
304 return true;
306 if (!source->IsAbsolute ()) {
307 //relative uri, not checking policy
308 return true;
311 Uri *target = new Uri ();
312 if (!target->Parse (location)) {
313 delete target;
314 return false;
317 bool retval = true;
318 switch (policy) {
319 case DownloaderPolicy:
320 //Allowed schemes: http, https
321 if (!target->IsScheme ("http") && !target->IsScheme ("https"))
322 retval = false;
323 //X-Scheme: no
324 if (!same_scheme (target, source))
325 retval = false;
326 //X-Domain: requires policy file
327 // FIXME only managed is implemented
328 if (!same_domain (target, source))
329 retval = false;
330 break;
331 case MsiPolicy:
332 case MediaPolicy: //Media, images, ASX
333 //Allowed schemes: http, https, file
334 if (!target->IsScheme ("http") && !target->IsScheme ("https") && !target->IsScheme ("file"))
335 retval = false;
336 //X-Scheme: no
337 if (!same_scheme (target, source))
338 retval = false;
339 //X-Domain: Allowed
340 break;
341 case XamlPolicy:
342 //Allowed schemes: http, https, file
343 if (!target->IsScheme ("http") && !target->IsScheme ("https") && !target->IsScheme ("file"))
344 retval = false;
345 //X-Scheme: no
346 if (!same_scheme (target, source))
347 retval =false;
348 //X-domain: allowed if not HTTPS to HTTPS
349 if (!same_domain (target, source) && target->IsScheme ("https") && source->IsScheme ("https"))
350 retval = false;
351 break;
352 case FontPolicy:
353 //Allowed schemes: http, https, file
354 if (!target->IsScheme ("http") && !target->IsScheme ("https") && !target->IsScheme ("file"))
355 retval = false;
356 //X-Scheme: no
357 if (!same_scheme (target, source))
358 retval = false;
359 //X-domain: no
360 if (!same_domain (target, source))
361 retval = false;
362 break;
363 case StreamingPolicy: //Streaming media
364 //Allowed schemes: http
365 if (!target->IsScheme ("http"))
366 retval = false;
367 //X-scheme: Not from https
368 if (source->IsScheme ("https") && !same_scheme (source, target))
369 retval = false;
370 //X-domain: allowed if not HTTPS to HTTPS
371 if (!same_domain (target, source) && target->IsScheme ("https") && source->IsScheme ("https"))
372 retval = false;
373 break;
374 default:
375 break;
378 delete target;
380 return retval;
383 void
384 Downloader::OpenInitialize ()
386 send_queued = false;
387 started = false;
388 aborted = false;
389 completed = false;
390 file_size = -2;
391 total = 0;
393 g_free (failed_msg);
394 g_free (filename);
395 g_free (buffer);
396 failed_msg = NULL;
397 filename = NULL;
398 buffer = NULL;
401 void
402 Downloader::Open (const char *verb, const char *uri, DownloaderAccessPolicy policy)
404 LOG_DOWNLOADER ("Downloader::Open (%s, %s)\n", verb, uri);
406 OpenInitialize ();
408 Uri *url = new Uri ();
409 if (url->Parse (uri))
410 Open (verb, url, policy);
412 delete url;
415 void
416 Downloader::Open (const char *verb, Uri *url, DownloaderAccessPolicy policy)
418 Uri *src_uri = NULL;
420 LOG_DOWNLOADER ("Downloader::Open (%s, %p)\n", verb, url);
422 OpenInitialize ();
424 access_policy = policy;
426 if (!url->isAbsolute) {
427 const char *source_location = NULL;
428 source_location = GetDeployment ()->GetXapLocation ();
429 if (source_location) {
430 src_uri = new Uri ();
431 if (!src_uri->Parse (source_location)) {
432 delete src_uri;
433 return;
435 src_uri->Combine (url);
436 url = src_uri;
440 //FIXME: ONLY VALIDATE IF USED FROM THE PLUGIN
441 char *location;
442 (location = g_strdup(GetDeployment ()->GetXapLocation ())) || (location = g_strdup(GetSurface ()->GetSourceLocation ()));
443 if (!validate_policy (location, url, policy)) {
444 LOG_DOWNLOADER ("aborting due to security policy violation\n");
445 failed_msg = g_strdup ("Security Policy Violation");
446 Abort ();
447 g_free (location);
448 delete src_uri;
449 return;
451 g_free (location);
453 if (url->GetScheme () != NULL && strcmp (url->GetScheme (), "mms") == 0) {
454 internal_dl = (InternalDownloader *) new MmsDownloader (this);
455 } else {
456 internal_dl = (InternalDownloader *) new FileDownloader (this);
459 send_queued = false;
461 SetUri (url);
462 char *struri = url->ToString ();
463 internal_dl->Open (verb, struri);
464 g_free (struri);
465 delete src_uri;
468 void
469 Downloader::InternalSetHeader (const char *header, const char *value)
471 LOG_DOWNLOADER ("Downloader::InternalSetHeader (%s, %s)\n", header, value);
473 header_func (downloader_state, header, value);
476 void
477 Downloader::InternalSetHeaderFormatted (const char *header, char *value)
479 InternalSetHeader (header, (const char *) value);
480 g_free (value);
483 void
484 Downloader::InternalSetBody (void *body, guint32 length)
486 LOG_DOWNLOADER ("Downloader::InternalSetBody (%p, %u)\n", body, length);
488 body_func (downloader_state, body, length);
491 void
492 Downloader::SendInternal ()
494 LOG_DOWNLOADER ("Downloader::SendInternal ()\n");
496 if (!GetSurface ()) {
497 // The plugin is already checking for surface before calling Send, so
498 // if we get here, it's either managed code doing something wrong or ourselves.
499 g_warning ("Downloader::SendInternal (): No surface!\n");
502 if (!send_queued)
503 return;
505 send_queued = false;
507 if (completed) {
508 // Consumer is re-sending a request which finished successfully.
509 NotifyFinished (NULL);
510 return;
513 if (failed_msg != NULL) {
514 // Consumer is re-sending a request which failed.
515 Emit (DownloadFailedEvent, new ErrorEventArgs (DownloadError, 1, failed_msg));
516 return;
519 started = true;
520 aborted = false;
522 send_func (downloader_state);
525 static void
526 send_async (EventObject *user_data)
528 Downloader *downloader = (Downloader *) user_data;
530 downloader->SendInternal ();
533 void
534 Downloader::Send ()
536 LOG_DOWNLOADER ("Downloader::Send ()\n");
538 if (!GetSurface ()) {
539 // The plugin is already checking for surface before calling Send, so
540 // if we get here, it's either managed code doing something wrong or ourselves.
541 g_warning ("Downloader::Send (): No surface!\n");
544 if (send_queued)
545 return;
547 send_queued = true;
548 SetStatusText ("");
549 SetStatus (0);
551 AddTickCall (send_async);
554 void
555 Downloader::SendNow ()
557 LOG_DOWNLOADER ("Downloader::SendNow ()\n");
559 send_queued = true;
560 SetStatusText ("");
561 SetStatus (0);
563 SendInternal ();
567 // A zero write means that we are done
569 void
570 Downloader::Write (void *buf, gint32 offset, gint32 n)
572 char* struri = NULL;
573 LOG_DOWNLOADER ("Downloader::Write (%p, %i, %i). Uri: %s\n", buf, offset, n, (struri = GetUri ()->ToString ()));
574 g_free (struri);
576 SetCurrentDeployment ();
578 if (aborted)
579 return;
581 if (!GetSurface ())
582 return;
584 internal_dl->Write (buf, offset, n);
587 void
588 Downloader::InternalWrite (void *buf, gint32 offset, gint32 n)
590 LOG_DOWNLOADER ("Downloader::InternalWrite (%p, %i, %i)\n", buf, offset, n);
592 double progress;
594 // Update progress
595 if (n > 0)
596 total += n;
598 if (file_size >= 0) {
599 if ((progress = total / (double) file_size) > 1.0)
600 progress = 1.0;
601 } else
602 progress = 0.0;
604 SetDownloadProgress (progress);
606 Emit (DownloadProgressChangedEvent);
608 if (writer)
609 writer (buf, offset, n, user_data);
611 // This is a horrible hack to work around mozilla bug #444160
612 // See Downloader::GetResponseText for an explanation
613 if (internal_dl->GetObjectType () == Type::FILEDOWNLOADER && n == total && total < 65536) {
614 buffer = (char *) g_malloc ((size_t) total);
615 memcpy (buffer, buf, (size_t) total);
619 void
620 Downloader::SetFilename (const char *fname)
622 LOG_DOWNLOADER ("Downloader::SetFilename (%s)\n", fname);
624 g_free (filename);
625 g_free (buffer);
626 buffer = NULL;
628 filename = g_strdup (fname);
630 internal_dl->SetFilename (filename);
633 void
634 Downloader::NotifyFinished (const char *final_uri)
636 if (aborted)
637 return;
639 SetCurrentDeployment ();
641 if (!GetSurface ())
642 return;
644 SetDownloadProgress (1.0);
646 Emit (DownloadProgressChangedEvent);
648 // HACK, we should provide the actual status text and code
649 SetStatusText ("OK");
650 SetStatus (200);
652 completed = true;
654 Emit (CompletedEvent, NULL);
657 void
658 Downloader::NotifyFailed (const char *msg)
660 LOG_DOWNLOADER ("Downloader::NotifyFailed (%s)\n", msg);
662 /* if we've already been notified of failure, no-op */
663 if (failed_msg)
664 return;
666 SetCurrentDeployment ();
668 if (!GetSurface ())
669 return;
671 // SetStatus (400);
672 // For some reason the status is 0, not updated on errors?
674 Emit (DownloadFailedEvent, new ErrorEventArgs (DownloadError, 1, msg));
676 // save the error in case someone else calls ::Send() on this
677 // downloader for the same uri.
678 failed_msg = g_strdup (msg);
681 void
682 Downloader::NotifySize (gint64 size)
684 LOG_DOWNLOADER ("Downloader::NotifySize (%lld)\n", size);
686 file_size = size;
688 if (aborted)
689 return;
691 SetCurrentDeployment ();
693 if (!GetSurface ())
694 return;
696 if (notify_size)
697 notify_size (size, user_data);
700 bool
701 Downloader::Started ()
703 LOG_DOWNLOADER ("Downloader::Started (): %i\n", started);
705 return started;
708 bool
709 Downloader::Completed ()
711 LOG_DOWNLOADER ("Downloader::Completed (), filename: %s\n", filename);
713 return completed;
716 void
717 Downloader::SetStreamFunctions (DownloaderWriteFunc writer,
718 DownloaderNotifySizeFunc notify_size,
719 gpointer user_data)
721 LOG_DOWNLOADER ("Downloader::SetStreamFunctions\n");
723 this->notify_size = notify_size;
724 this->writer = writer;
725 this->user_data = user_data;
728 void
729 Downloader::SetFunctions (DownloaderCreateStateFunc create_state,
730 DownloaderDestroyStateFunc destroy_state,
731 DownloaderOpenFunc open,
732 DownloaderSendFunc send,
733 DownloaderAbortFunc abort,
734 DownloaderHeaderFunc header,
735 DownloaderBodyFunc body,
736 DownloaderCreateWebRequestFunc request,
737 DownloaderSetResponseHeaderCallbackFunc response_header_callback,
738 DownloaderGetResponseFunc get_response)
740 LOG_DOWNLOADER ("Downloader::SetFunctions\n");
741 Downloader::create_state = create_state;
742 Downloader::destroy_state = destroy_state;
743 Downloader::open_func = open;
744 Downloader::send_func = send;
745 Downloader::abort_func = abort;
746 Downloader::header_func = header;
747 Downloader::body_func = body;
748 Downloader::request_func = request;
749 Downloader::set_response_header_callback_func = response_header_callback;
750 Downloader::get_response_func = get_response;
755 * DownloaderRequest / DownloaderResponse
758 DownloaderResponse::~DownloaderResponse ()
760 if (request != NULL && request->GetDownloaderResponse () == this)
761 request->SetDownloaderResponse (NULL);
762 GetDeployment ()->UnregisterDownloader (this);
765 DownloaderResponse::DownloaderResponse ()
767 aborted = false;
768 started = NULL;
769 available = NULL;
770 finished = NULL;
771 context = NULL;
772 request = NULL;
773 SetDeployment (Deployment::GetCurrent ());
774 GetDeployment ()->RegisterDownloader (this);
777 DownloaderResponse::DownloaderResponse (DownloaderResponseStartedHandler started, DownloaderResponseDataAvailableHandler available, DownloaderResponseFinishedHandler finished, gpointer context)
779 this->aborted = false;
780 this->started = started;
781 this->available = available;
782 this->finished = finished;
783 this->context = context;
784 this->request = NULL;
785 SetDeployment (Deployment::GetCurrent ());
786 GetDeployment ()->RegisterDownloader (this);
789 DownloaderRequest::DownloaderRequest (const char *method, const char *uri)
791 this->method = g_strdup (method);
792 this->uri = g_strdup (uri);
793 this->response = NULL;
794 SetDeployment (Deployment::GetCurrent ());
795 GetDeployment ()->RegisterDownloader (this);
798 DownloaderRequest::~DownloaderRequest ()
800 g_free (method);
801 g_free (uri);
802 if (response != NULL && response->GetDownloaderRequest () == this)
803 response->SetDownloaderRequest (NULL);
804 GetDeployment ()->UnregisterDownloader (this);
807 void *
808 Downloader::CreateWebRequest (const char *method, const char *uri)
810 return GetRequestFunc () (method, uri, GetContext ());
813 void
814 Downloader::SetResponseHeaderCallback (DownloaderResponseHeaderCallback callback, gpointer context)
816 if (set_response_header_callback_func != NULL)
817 set_response_header_callback_func (downloader_state, callback, context);
820 DownloaderResponse *
821 Downloader::GetResponse ()
823 if (get_response_func != NULL)
824 return get_response_func (downloader_state);
825 return NULL;
828 void
829 downloader_write (Downloader *dl, void *buf, gint32 offset, gint32 n)
831 dl->Write (buf, offset, n);
834 void
835 downloader_notify_finished (Downloader *dl, const char *fname)
837 dl->SetFilename (fname);
838 dl->NotifyFinished (NULL);
841 void
842 downloader_notify_error (Downloader *dl, const char *msg)
844 dl->NotifyFailed (msg);
847 void
848 downloader_notify_size (Downloader *dl, gint64 size)
850 dl->NotifySize (size);
854 static gpointer
855 dummy_downloader_create_state (Downloader* dl)
857 g_warning ("downloader_set_function has never been called.\n");
858 return NULL;
861 static void
862 dummy_downloader_destroy_state (gpointer state)
864 g_warning ("downloader_set_function has never been called.\n");
867 static void
868 dummy_downloader_open (gpointer state, const char *verb, const char *uri, bool custom_header_support, bool disble_cache)
870 g_warning ("downloader_set_function has never been called.\n");
873 static void
874 dummy_downloader_send (gpointer state)
876 g_warning ("downloader_set_function has never been called.\n");
879 static void
880 dummy_downloader_abort (gpointer state)
882 g_warning ("downloader_set_function has never been called.\n");
885 static void
886 dummy_downloader_header (gpointer state, const char *header, const char *value)
888 g_warning ("downloader_set_function has never been called.\n");
891 static void
892 dummy_downloader_body (gpointer state, void *body, guint32 length)
894 g_warning ("downloader_set_function has never been called.\n");
897 static gpointer
898 dummy_downloader_create_web_request (const char *method, const char *uri, gpointer context)
900 g_warning ("downloader_set_function has never been called.\n");
901 return NULL;
904 static void
905 dummy_downloader_set_response_header_callback (gpointer state, DownloaderResponseHeaderCallback callback, gpointer context)
907 g_warning ("downloader_set_function has never been called.\n");
910 static DownloaderResponse *
911 dummy_downloader_get_response (gpointer state)
913 g_warning ("downloader_set_function has never been called.\n");
914 return NULL;
917 DownloaderCreateStateFunc Downloader::create_state = dummy_downloader_create_state;
918 DownloaderDestroyStateFunc Downloader::destroy_state = dummy_downloader_destroy_state;
919 DownloaderOpenFunc Downloader::open_func = dummy_downloader_open;
920 DownloaderSendFunc Downloader::send_func = dummy_downloader_send;
921 DownloaderAbortFunc Downloader::abort_func = dummy_downloader_abort;
922 DownloaderHeaderFunc Downloader::header_func = dummy_downloader_header;
923 DownloaderBodyFunc Downloader::body_func = dummy_downloader_body;
924 DownloaderCreateWebRequestFunc Downloader::request_func = dummy_downloader_create_web_request;
925 DownloaderSetResponseHeaderCallbackFunc Downloader::set_response_header_callback_func = dummy_downloader_set_response_header_callback;
926 DownloaderGetResponseFunc Downloader::get_response_func = dummy_downloader_get_response;
928 void
929 downloader_init (void)