Subversion Repositories Kolibri OS

Rev

Rev 4364 | Go to most recent revision | Blame | Last modification | View Log | RSS feed

  1. /*
  2.  * Copyright 2006,2007 Daniel Silverstone <dsilvers@digital-scurf.org>
  3.  * Copyright 2007 James Bursa <bursa@users.sourceforge.net>
  4.  * Copyright 2003 Phil Mellor <monkeyson@users.sourceforge.net>
  5.  *
  6.  * This file is part of NetSurf, http://www.netsurf-browser.org/
  7.  *
  8.  * NetSurf is free software; you can redistribute it and/or modify
  9.  * it under the terms of the GNU General Public License as published by
  10.  * the Free Software Foundation; version 2 of the License.
  11.  *
  12.  * NetSurf is distributed in the hope that it will be useful,
  13.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  15.  * GNU General Public License for more details.
  16.  *
  17.  * You should have received a copy of the GNU General Public License
  18.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  19.  */
  20.  
  21. /** \file
  22.  * Fetching of data from a URL (implementation).
  23.  *
  24.  * Active fetches are held in the circular linked list ::fetch_ring. There may
  25.  * be at most ::option_max_fetchers_per_host active requests per Host: header.
  26.  * There may be at most ::option_max_fetchers active requests overall. Inactive
  27.  * fetchers are stored in the ::queue_ring waiting for use.
  28.  */
  29.  
  30. #include <assert.h>
  31. #include <errno.h>
  32. #include <stdbool.h>
  33. #include <string.h>
  34. #include <strings.h>
  35. #include <time.h>
  36.  
  37. #include <libwapcaplet/libwapcaplet.h>
  38.  
  39. #include "utils/config.h"
  40. #include "content/fetch.h"
  41. #include "content/fetchers/resource.h"
  42. #include "content/fetchers/about.h"
  43. #include "content/fetchers/curl.h"
  44. #include "content/fetchers/data.h"
  45. #include "content/fetchers/file.h"
  46. #include "content/urldb.h"
  47. #include "desktop/netsurf.h"
  48. #include "desktop/options.h"
  49. #include "utils/log.h"
  50. #include "utils/messages.h"
  51. #include "utils/nsurl.h"
  52. #include "utils/utils.h"
  53. #include "utils/ring.h"
  54.  
  55. /* Define this to turn on verbose fetch logging */
  56. #undef DEBUG_FETCH_VERBOSE
  57.  
  58. bool fetch_active;      /**< Fetches in progress, please call fetch_poll(). */
  59.  
  60. /** Information about a fetcher for a given scheme. */
  61. typedef struct scheme_fetcher_s {
  62.         lwc_string *scheme_name;                /**< The scheme. */
  63.         fetcher_can_fetch can_fetch;            /**< Ensure an URL can be fetched. */
  64.         fetcher_setup_fetch setup_fetch;        /**< Set up a fetch. */
  65.         fetcher_start_fetch start_fetch;        /**< Start a fetch. */
  66.         fetcher_abort_fetch abort_fetch;        /**< Abort a fetch. */
  67.         fetcher_free_fetch free_fetch;          /**< Free a fetch. */
  68.         fetcher_poll_fetcher poll_fetcher;      /**< Poll this fetcher. */
  69.         fetcher_finalise finaliser;             /**< Clean up this fetcher. */
  70.         int refcount;                           /**< When zero, clean up the fetcher. */
  71.         struct scheme_fetcher_s *next_fetcher;  /**< Next fetcher in the list. */
  72.         struct scheme_fetcher_s *prev_fetcher;  /**< Prev fetcher in the list. */
  73. } scheme_fetcher;
  74.  
  75. static scheme_fetcher *fetchers = NULL;
  76.  
  77. /** Information for a single fetch. */
  78. struct fetch {
  79.         fetch_callback callback;/**< Callback function. */
  80.         nsurl *url;             /**< URL. */
  81.         nsurl *referer;         /**< Referer URL. */
  82.         bool send_referer;      /**< Valid to send the referer */
  83.         bool verifiable;        /**< Transaction is verifiable */
  84.         void *p;                /**< Private data for callback. */
  85.         lwc_string *host;       /**< Host part of URL, interned */
  86.         long http_code;         /**< HTTP response code, or 0. */
  87.         scheme_fetcher *ops;    /**< Fetcher operations for this fetch,
  88.                                      NULL if not set. */
  89.         void *fetcher_handle;   /**< The handle for the fetcher. */
  90.         bool fetch_is_active;   /**< This fetch is active. */
  91.         struct fetch *r_prev;   /**< Previous active fetch in ::fetch_ring. */
  92.         struct fetch *r_next;   /**< Next active fetch in ::fetch_ring. */
  93. };
  94.  
  95. static struct fetch *fetch_ring = 0;    /**< Ring of active fetches. */
  96. static struct fetch *queue_ring = 0;    /**< Ring of queued fetches */
  97.  
  98. #define fetch_ref_fetcher(F) F->refcount++
  99. static void fetch_unref_fetcher(scheme_fetcher *fetcher);
  100. static void fetch_dispatch_jobs(void);
  101. static bool fetch_choose_and_dispatch(void);
  102. static bool fetch_dispatch_job(struct fetch *fetch);
  103.  
  104. /* Static lwc_strings */
  105. static lwc_string *fetch_http_lwc;
  106. static lwc_string *fetch_https_lwc;
  107.  
  108.  
  109. /**
  110.  * Initialise the fetcher.
  111.  */
  112.  
  113. void fetch_init(void)
  114. {
  115.         fetch_curl_register();
  116.         fetch_data_register();
  117.         fetch_file_register();
  118.         fetch_resource_register();
  119.         fetch_about_register();
  120.         fetch_active = false;
  121.  
  122.         if (lwc_intern_string("http", SLEN("http"), &fetch_http_lwc) !=
  123.                         lwc_error_ok) {
  124.                 die("Failed to initialise the fetch module "
  125.                                 "(couldn't intern \"http\").");
  126.         }
  127.  
  128.         if (lwc_intern_string("https", SLEN("https"), &fetch_https_lwc) !=
  129.                         lwc_error_ok) {
  130.                 die("Failed to initialise the fetch module "
  131.                                 "(couldn't intern \"https\").");
  132.         }
  133. }
  134.  
  135.  
  136. /**
  137.  * Clean up for quit.
  138.  *
  139.  * Must be called before exiting.
  140.  */
  141.  
  142. void fetch_quit(void)
  143. {
  144.         while (fetchers != NULL) {
  145.                 if (fetchers->refcount != 1) {
  146.                         LOG(("Fetcher for scheme %s still active?!",
  147.                                         lwc_string_data(fetchers->scheme_name)));
  148.                         /* We shouldn't do this, but... */
  149.                         fetchers->refcount = 1;
  150.                 }
  151.                 fetch_unref_fetcher(fetchers);
  152.         }
  153.  
  154.         lwc_string_unref(fetch_http_lwc);
  155.         lwc_string_unref(fetch_https_lwc);
  156. }
  157.  
  158.  
  159. bool fetch_add_fetcher(lwc_string *scheme,
  160.                   fetcher_initialise initialiser,
  161.                   fetcher_can_fetch can_fetch,
  162.                   fetcher_setup_fetch setup_fetch,
  163.                   fetcher_start_fetch start_fetch,
  164.                   fetcher_abort_fetch abort_fetch,
  165.                   fetcher_free_fetch free_fetch,
  166.                   fetcher_poll_fetcher poll_fetcher,
  167.                   fetcher_finalise finaliser)
  168. {
  169.         scheme_fetcher *new_fetcher;
  170.         if (!initialiser(scheme))
  171.                 return false;
  172.         new_fetcher = malloc(sizeof(scheme_fetcher));
  173.         if (new_fetcher == NULL) {
  174.                 finaliser(scheme);
  175.                 return false;
  176.         }
  177.         new_fetcher->scheme_name = scheme;
  178.         new_fetcher->refcount = 0;
  179.         new_fetcher->can_fetch = can_fetch;
  180.         new_fetcher->setup_fetch = setup_fetch;
  181.         new_fetcher->start_fetch = start_fetch;
  182.         new_fetcher->abort_fetch = abort_fetch;
  183.         new_fetcher->free_fetch = free_fetch;
  184.         new_fetcher->poll_fetcher = poll_fetcher;
  185.         new_fetcher->finaliser = finaliser;
  186.         new_fetcher->next_fetcher = fetchers;
  187.         fetchers = new_fetcher;
  188.         fetch_ref_fetcher(new_fetcher);
  189.         return true;
  190. }
  191.  
  192.  
  193. void fetch_unref_fetcher(scheme_fetcher *fetcher)
  194. {
  195.         if (--fetcher->refcount == 0) {
  196.                 fetcher->finaliser(fetcher->scheme_name);
  197.                 lwc_string_unref(fetcher->scheme_name);
  198.                 if (fetcher == fetchers) {
  199.                         fetchers = fetcher->next_fetcher;
  200.                         if (fetchers)
  201.                                 fetchers->prev_fetcher = NULL;
  202.                 } else {
  203.                         fetcher->prev_fetcher->next_fetcher =
  204.                                         fetcher->next_fetcher;
  205.                         if (fetcher->next_fetcher != NULL)
  206.                                 fetcher->next_fetcher->prev_fetcher =
  207.                                                 fetcher->prev_fetcher;
  208.                 }
  209.                 free(fetcher);
  210.         }
  211. }
  212.  
  213.  
  214. /**
  215.  * Start fetching data for the given URL.
  216.  *
  217.  * The function returns immediately. The fetch may be queued for later
  218.  * processing.
  219.  *
  220.  * A pointer to an opaque struct fetch is returned, which can be passed to
  221.  * fetch_abort() to abort the fetch at any time. Returns 0 if memory is
  222.  * exhausted (or some other fatal error occurred).
  223.  *
  224.  * The caller must supply a callback function which is called when anything
  225.  * interesting happens. The callback function is first called with msg
  226.  * FETCH_HEADER, with the header in data, then one or more times
  227.  * with FETCH_DATA with some data for the url, and finally with
  228.  * FETCH_FINISHED. Alternatively, FETCH_ERROR indicates an error occurred:
  229.  * data contains an error message. FETCH_REDIRECT may replace the FETCH_HEADER,
  230.  * FETCH_DATA, FETCH_FINISHED sequence if the server sends a replacement URL.
  231.  *
  232.  */
  233.  
  234. struct fetch * fetch_start(nsurl *url, nsurl *referer,
  235.                            fetch_callback callback,
  236.                            void *p, bool only_2xx, const char *post_urlenc,
  237.                            const struct fetch_multipart_data *post_multipart,
  238.                            bool verifiable, bool downgrade_tls,
  239.                            const char *headers[])
  240. {
  241.         struct fetch *fetch;
  242.         scheme_fetcher *fetcher = fetchers;
  243.         lwc_string *scheme;
  244.         bool match;
  245.  
  246.         fetch = malloc(sizeof (*fetch));
  247.         if (fetch == NULL)
  248.                 return NULL;
  249.  
  250.         /* The URL we're fetching must have a scheme */
  251.         scheme = nsurl_get_component(url, NSURL_SCHEME);
  252.         assert(scheme != NULL);
  253.  
  254. #ifdef DEBUG_FETCH_VERBOSE
  255.         LOG(("fetch %p, url '%s'", fetch, nsurl_access(url)));
  256. #endif
  257.  
  258.         /* construct a new fetch structure */
  259.         fetch->callback = callback;
  260.         fetch->url = nsurl_ref(url);
  261.         fetch->verifiable = verifiable;
  262.         fetch->p = p;
  263.         fetch->http_code = 0;
  264.         fetch->r_prev = NULL;
  265.         fetch->r_next = NULL;
  266.         fetch->referer = NULL;
  267.         fetch->send_referer = false;
  268.         fetch->fetcher_handle = NULL;
  269.         fetch->ops = NULL;
  270.         fetch->fetch_is_active = false;
  271.         fetch->host = nsurl_get_component(url, NSURL_HOST);
  272.        
  273.         if (referer != NULL) {
  274.                 lwc_string *ref_scheme;
  275.                 fetch->referer = nsurl_ref(referer);
  276.  
  277.                 ref_scheme = nsurl_get_component(referer, NSURL_SCHEME);
  278.                 /* Not a problem if referer has no scheme */
  279.  
  280.                 /* Determine whether to send the Referer header */
  281.                 if (nsoption_bool(send_referer) && ref_scheme != NULL) {
  282.                         /* User permits us to send the header
  283.                          * Only send it if:
  284.                          *    1) The fetch and referer schemes match
  285.                          * or 2) The fetch is https and the referer is http
  286.                          *
  287.                          * This ensures that referer information is only sent
  288.                          * across schemes in the special case of an https
  289.                          * request from a page served over http. The inverse
  290.                          * (https -> http) should not send the referer (15.1.3)
  291.                          */
  292.                         bool match1;
  293.                         bool match2;
  294.                         if (lwc_string_isequal(scheme, ref_scheme, &match) != lwc_error_ok) {
  295.                                 match = false;
  296.                         }
  297.                         if (lwc_string_isequal(scheme, fetch_https_lwc, &match1) != lwc_error_ok) {
  298.                                 match1 = false;
  299.                         }
  300.                         if (lwc_string_isequal(ref_scheme, fetch_http_lwc, &match2) != lwc_error_ok) {
  301.                                 match2= false;
  302.                         }
  303.                         if (match == true || (match1 == true && match2 == true))
  304.                                 fetch->send_referer = true;
  305.                 }
  306.                 if (ref_scheme != NULL)
  307.                         lwc_string_unref(ref_scheme);
  308.         }
  309.  
  310.         /* Pick the scheme ops */
  311.         while (fetcher) {
  312.                 if ((lwc_string_isequal(fetcher->scheme_name, scheme,
  313.                                 &match) == lwc_error_ok) && (match == true)) {
  314.                         fetch->ops = fetcher;
  315.                         break;
  316.                 }
  317.                 fetcher = fetcher->next_fetcher;
  318.         }
  319.  
  320.         if (fetch->ops == NULL)
  321.                 goto failed;
  322.  
  323.         /* Got a scheme fetcher, try and set up the fetch */
  324.         fetch->fetcher_handle = fetch->ops->setup_fetch(fetch, url,
  325.                                         only_2xx, downgrade_tls,
  326.                                         post_urlenc, post_multipart,
  327.                                         headers);
  328.  
  329.         if (fetch->fetcher_handle == NULL)
  330.                 goto failed;
  331.  
  332.         /* Rah, got it, so ref the fetcher. */
  333.         fetch_ref_fetcher(fetch->ops);
  334.  
  335.         /* these aren't needed past here */
  336.         lwc_string_unref(scheme);
  337.  
  338.         /* Dump us in the queue and ask the queue to run. */
  339.         RING_INSERT(queue_ring, fetch);
  340.         fetch_dispatch_jobs();
  341.  
  342.         return fetch;
  343.  
  344. failed:
  345.         lwc_string_unref(scheme);
  346.  
  347.         if (fetch->host != NULL)
  348.                 lwc_string_unref(fetch->host);
  349.         if (fetch->url != NULL)
  350.                 nsurl_unref(fetch->url);
  351.         if (fetch->referer != NULL)
  352.                 nsurl_unref(fetch->referer);
  353.  
  354.         free(fetch);
  355.  
  356.         return NULL;
  357. }
  358.  
  359.  
  360. /**
  361.  * Dispatch as many jobs as we have room to dispatch.
  362.  */
  363. void fetch_dispatch_jobs(void)
  364. {
  365.         int all_active, all_queued;
  366. #ifdef DEBUG_FETCH_VERBOSE
  367.         struct fetch *q;
  368.         struct fetch *f;
  369. #endif
  370.  
  371.         if (!queue_ring)
  372.                 return; /* Nothing to do, the queue is empty */
  373.         RING_GETSIZE(struct fetch, queue_ring, all_queued);
  374.         RING_GETSIZE(struct fetch, fetch_ring, all_active);
  375.  
  376. #ifdef DEBUG_FETCH_VERBOSE
  377.         LOG(("queue_ring %i, fetch_ring %i", all_queued, all_active));
  378.  
  379.         q = queue_ring;
  380.         if (q) {
  381.                 do {
  382.                         LOG(("queue_ring: %s", q->url));
  383.                         q = q->r_next;
  384.                 } while (q != queue_ring);
  385.         }
  386.         f = fetch_ring;
  387.         if (f) {
  388.                 do {
  389.                         LOG(("fetch_ring: %s", f->url));
  390.                         f = f->r_next;
  391.                 } while (f != fetch_ring);
  392.         }
  393. #endif
  394.  
  395.         while ( all_queued && all_active < nsoption_int(max_fetchers) ) {
  396.                 /*LOG(("%d queued, %d fetching", all_queued, all_active));*/
  397.                 if (fetch_choose_and_dispatch()) {
  398.                         all_queued--;
  399.                         all_active++;
  400.                 } else {
  401.                         /* Either a dispatch failed or we ran out. Just stop */
  402.                         break;
  403.                 }
  404.         }
  405.         fetch_active = (all_active > 0);
  406. #ifdef DEBUG_FETCH_VERBOSE
  407.         LOG(("Fetch ring is now %d elements.", all_active));
  408.         LOG(("Queue ring is now %d elements.", all_queued));
  409. #endif
  410. }
  411.  
  412.  
  413. /**
  414.  * Choose and dispatch a single job. Return false if we failed to dispatch
  415.  * anything.
  416.  *
  417.  * We don't check the overall dispatch size here because we're not called unless
  418.  * there is room in the fetch queue for us.
  419.  */
  420. bool fetch_choose_and_dispatch(void)
  421. {
  422.         bool same_host;
  423.         struct fetch *queueitem;
  424.         queueitem = queue_ring;
  425.         do {
  426.                 /* We can dispatch the selected item if there is room in the
  427.                  * fetch ring
  428.                  */
  429.                 int countbyhost;
  430.                 RING_COUNTBYLWCHOST(struct fetch, fetch_ring, countbyhost,
  431.                                 queueitem->host);
  432.                 if (countbyhost < nsoption_int(max_fetchers_per_host)) {
  433.                         /* We can dispatch this item in theory */
  434.                         return fetch_dispatch_job(queueitem);
  435.                 }
  436.                 /* skip over other items with the same host */
  437.                 same_host = true;
  438.                 while (same_host == true && queueitem->r_next != queue_ring) {
  439.                         if (lwc_string_isequal(queueitem->host,
  440.                                         queueitem->r_next->host, &same_host) ==
  441.                                         lwc_error_ok && same_host == true) {
  442.                                 queueitem = queueitem->r_next;
  443.                         }
  444.                 }
  445.                 queueitem = queueitem->r_next;
  446.         } while (queueitem != queue_ring);
  447.         return false;
  448. }
  449.  
  450.  
  451. /**
  452.  * Dispatch a single job
  453.  */
  454. bool fetch_dispatch_job(struct fetch *fetch)
  455. {
  456.         RING_REMOVE(queue_ring, fetch);
  457. #ifdef DEBUG_FETCH_VERBOSE
  458.         LOG(("Attempting to start fetch %p, fetcher %p, url %s", fetch,
  459.                         fetch->fetcher_handle, nsurl_access(fetch->url)));
  460. #endif
  461.         if (!fetch->ops->start_fetch(fetch->fetcher_handle)) {
  462.                 RING_INSERT(queue_ring, fetch); /* Put it back on the end of the queue */
  463.                 return false;
  464.         } else {
  465.                 RING_INSERT(fetch_ring, fetch);
  466.                 fetch->fetch_is_active = true;
  467.                 return true;
  468.         }
  469. }
  470.  
  471.  
  472. /**
  473.  * Abort a fetch.
  474.  */
  475.  
  476. void fetch_abort(struct fetch *f)
  477. {
  478.         assert(f);
  479. #ifdef DEBUG_FETCH_VERBOSE
  480.         LOG(("fetch %p, fetcher %p, url '%s'", f, f->fetcher_handle,
  481.                         nsurl_access(f->url)));
  482. #endif
  483.         f->ops->abort_fetch(f->fetcher_handle);
  484. }
  485.  
  486.  
  487. /**
  488.  * Free a fetch structure and associated resources.
  489.  */
  490.  
  491. void fetch_free(struct fetch *f)
  492. {
  493. #ifdef DEBUG_FETCH_VERBOSE
  494.         LOG(("Freeing fetch %p, fetcher %p", f, f->fetcher_handle));
  495. #endif
  496.         f->ops->free_fetch(f->fetcher_handle);
  497.         fetch_unref_fetcher(f->ops);
  498.         nsurl_unref(f->url);
  499.         if (f->referer != NULL)
  500.                 nsurl_unref(f->referer);
  501.         if (f->host != NULL)
  502.                 lwc_string_unref(f->host);
  503.         free(f);
  504. }
  505.  
  506.  
  507. /**
  508.  * Do some work on current fetches.
  509.  *
  510.  * Must be called regularly to make progress on fetches.
  511.  */
  512.  
  513. void fetch_poll(void)
  514. {
  515.         scheme_fetcher *fetcher = fetchers;
  516.         scheme_fetcher *next_fetcher;
  517.  
  518.         fetch_dispatch_jobs();
  519.  
  520.         if (!fetch_active)
  521.                 return; /* No point polling, there's no fetch active. */
  522.         while (fetcher != NULL) {
  523.                 next_fetcher = fetcher->next_fetcher;
  524.                 if (fetcher->poll_fetcher != NULL) {
  525.                         /* LOG(("Polling fetcher for %s",
  526.                            lwc_string_data(fetcher->scheme_name))); */
  527.                         fetcher->poll_fetcher(fetcher->scheme_name);
  528.                 }
  529.                 fetcher = next_fetcher;
  530.         }
  531. }
  532.  
  533.  
  534. /**
  535.  * Check if a URL's scheme can be fetched.
  536.  *
  537.  * \param  url  URL to check
  538.  * \return  true if the scheme is supported
  539.  */
  540.  
  541. bool fetch_can_fetch(const nsurl *url)
  542. {
  543.         scheme_fetcher *fetcher = fetchers;
  544.         bool match;
  545.         lwc_string *scheme = nsurl_get_component(url, NSURL_SCHEME);
  546.  
  547.         while (fetcher != NULL) {
  548.                 if (lwc_string_isequal(fetcher->scheme_name, scheme, &match) == lwc_error_ok && match == true) {
  549.                         break;
  550.                 }
  551.  
  552.                 fetcher = fetcher->next_fetcher;
  553.         }
  554.  
  555.         lwc_string_unref(scheme);
  556.  
  557.         return fetcher == NULL ? false : fetcher->can_fetch(url);
  558. }
  559.  
  560.  
  561. /**
  562.  * Change the callback function for a fetch.
  563.  */
  564.  
  565. void fetch_change_callback(struct fetch *fetch,
  566.                            fetch_callback callback,
  567.                            void *p)
  568. {
  569.         assert(fetch);
  570.         fetch->callback = callback;
  571.         fetch->p = p;
  572. }
  573.  
  574.  
  575. /**
  576.  * Get the HTTP response code.
  577.  */
  578.  
  579. long fetch_http_code(struct fetch *fetch)
  580. {
  581.         return fetch->http_code;
  582. }
  583.  
  584. /**
  585.  * Determine if a fetch was verifiable
  586.  *
  587.  * \param fetch  Fetch to consider
  588.  * \return Verifiable status of fetch
  589.  */
  590. bool fetch_get_verifiable(struct fetch *fetch)
  591. {
  592.         assert(fetch);
  593.  
  594.         return fetch->verifiable;
  595. }
  596.  
  597. /**
  598.  * Clone a linked list of fetch_multipart_data.
  599.  *
  600.  * \param list  List to clone
  601.  * \return Pointer to head of cloned list, or NULL on failure
  602.  */
  603. struct fetch_multipart_data *fetch_multipart_data_clone(
  604.                 const struct fetch_multipart_data *list)
  605. {
  606.         struct fetch_multipart_data *clone, *last = NULL;
  607.         struct fetch_multipart_data *result = NULL;
  608.  
  609.         for (; list != NULL; list = list->next) {
  610.                 clone = malloc(sizeof(struct fetch_multipart_data));
  611.                 if (clone == NULL) {
  612.                         if (result != NULL)
  613.                                 fetch_multipart_data_destroy(result);
  614.  
  615.                         return NULL;
  616.                 }
  617.  
  618.                 clone->file = list->file;
  619.  
  620.                 clone->name = strdup(list->name);
  621.                 if (clone->name == NULL) {
  622.                         free(clone);
  623.                         if (result != NULL)
  624.                                 fetch_multipart_data_destroy(result);
  625.  
  626.                         return NULL;
  627.                 }
  628.  
  629.                 clone->value = strdup(list->value);
  630.                 if (clone->value == NULL) {
  631.                         free(clone->name);
  632.                         free(clone);
  633.                         if (result != NULL)
  634.                                 fetch_multipart_data_destroy(result);
  635.  
  636.                         return NULL;
  637.                 }
  638.  
  639.                 clone->next = NULL;
  640.  
  641.                 if (result == NULL)
  642.                         result = clone;
  643.                 else
  644.                         last->next = clone;
  645.  
  646.                 last = clone;
  647.         }
  648.  
  649.         return result;
  650. }
  651.  
  652. /**
  653.  * Free a linked list of fetch_multipart_data.
  654.  *
  655.  * \param list Pointer to head of list to free
  656.  */
  657. void fetch_multipart_data_destroy(struct fetch_multipart_data *list)
  658. {
  659.         struct fetch_multipart_data *next;
  660.  
  661.         for (; list != NULL; list = next) {
  662.                 next = list->next;
  663.                 free(list->name);
  664.                 free(list->value);
  665.                 free(list);
  666.         }
  667. }
  668.  
  669. void
  670. fetch_send_callback(const fetch_msg *msg, struct fetch *fetch)
  671. {
  672.         __menuet__debug_out("Inside fetch_send_callback\n");
  673.  
  674.         fetch->callback(msg, fetch->p);
  675.         __menuet__debug_out("After fetch->callback \n");
  676. }
  677.  
  678.  
  679. void fetch_remove_from_queues(struct fetch *fetch)
  680. {
  681.         int all_active, all_queued;
  682.  
  683.         /* Go ahead and free the fetch properly now */
  684. #ifdef DEBUG_FETCH_VERBOSE
  685.         LOG(("Fetch %p, fetcher %p can be freed", fetch, fetch->fetcher_handle));
  686. #endif
  687.  
  688.         if (fetch->fetch_is_active) {
  689.                 RING_REMOVE(fetch_ring, fetch);
  690.         } else {
  691.                 RING_REMOVE(queue_ring, fetch);
  692.         }
  693.  
  694.         RING_GETSIZE(struct fetch, fetch_ring, all_active);
  695.         RING_GETSIZE(struct fetch, queue_ring, all_queued);
  696.  
  697.         fetch_active = (all_active > 0);
  698.  
  699. #ifdef DEBUG_FETCH_VERBOSE
  700.         LOG(("Fetch ring is now %d elements.", all_active));
  701.         LOG(("Queue ring is now %d elements.", all_queued));
  702. #endif
  703. }
  704.  
  705.  
  706. void
  707. fetch_set_http_code(struct fetch *fetch, long http_code)
  708. {
  709. #ifdef DEBUG_FETCH_VERBOSE
  710.         LOG(("Setting HTTP code to %ld", http_code));
  711. #endif
  712.         fetch->http_code = http_code;
  713. }
  714.  
  715. const char *fetch_get_referer_to_send(struct fetch *fetch)
  716. {
  717.         if (fetch->send_referer)
  718.                 return nsurl_access(fetch->referer);
  719.         return NULL;
  720. }
  721.  
  722. void
  723. fetch_set_cookie(struct fetch *fetch, const char *data)
  724. {
  725.         assert(fetch && data);
  726.  
  727.         /* If the fetch is unverifiable err on the side of caution and
  728.          * do not set the cookie */
  729.  
  730.         if (fetch->verifiable) {
  731.                 /* If the transaction's verifiable, we don't require
  732.                  * that the request uri and the parent domain match,
  733.                  * so don't pass in any referer/parent in this case. */
  734.                 urldb_set_cookie(data, fetch->url, NULL);
  735.         } else if (fetch->referer != NULL) {
  736.                 /* Permit the cookie to be set if the fetch is unverifiable
  737.                  * and the fetch URI domain matches the referer. */
  738.                 /** \todo Long-term, this needs to be replaced with a
  739.                  * comparison against the origin fetch URI. In the case
  740.                  * where a nested object requests a fetch, the origin URI
  741.                  * is the nested object's parent URI, whereas the referer
  742.                  * for the fetch will be the nested object's URI. */
  743.                 urldb_set_cookie(data, fetch->url, fetch->referer);
  744.         }
  745. }
  746.  
  747.