Subversion Repositories Kolibri OS

Rev

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