Subversion Repositories Kolibri OS

Rev

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

  1. /*
  2.  * Copyright 2009 John-Mark Bell <jmb@netsurf-browser.org>
  3.  *
  4.  * This file is part of NetSurf, http://www.netsurf-browser.org/
  5.  *
  6.  * NetSurf is free software; you can redistribute it and/or modify
  7.  * it under the terms of the GNU General Public License as published by
  8.  * the Free Software Foundation; version 2 of the License.
  9.  *
  10.  * NetSurf is distributed in the hope that it will be useful,
  11.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  12.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  13.  * GNU General Public License for more details.
  14.  *
  15.  * You should have received a copy of the GNU General Public License
  16.  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
  17.  */
  18.  
  19. /** \file
  20.  * Low-level resource cache (implementation)
  21.  */
  22.  
  23. #include <stdlib.h>
  24. #include <string.h>
  25. #include <time.h>
  26.  
  27. #include <curl/curl.h>
  28.  
  29. #include "content/fetch.h"
  30. #include "content/llcache.h"
  31. #include "content/urldb.h"
  32. #include "utils/log.h"
  33. #include "utils/messages.h"
  34. #include "utils/nsurl.h"
  35. #include "utils/utils.h"
  36.  
  37. /** Define to enable tracing of llcache operations. */
  38. #undef LLCACHE_TRACE
  39.  
  40. #ifdef DBG
  41. #undef DBG
  42. #endif
  43. //#define DBG(s) __menuet__debug_out(s) /* For the debug messages in BOARD */
  44. #define DBG(s) LOG((s))            /* So that we see debug in Netsurf's LOG files */
  45.  
  46.  
  47. /** State of a low-level cache object fetch */
  48. typedef enum {
  49.         LLCACHE_FETCH_INIT,             /**< Initial state, before fetch */
  50.         LLCACHE_FETCH_HEADERS,          /**< Fetching headers */
  51.         LLCACHE_FETCH_DATA,             /**< Fetching object data */
  52.         LLCACHE_FETCH_COMPLETE          /**< Fetch completed */
  53. } llcache_fetch_state;
  54.  
  55. /** Type of low-level cache object */
  56. typedef struct llcache_object llcache_object;
  57.  
  58. /** Handle to low-level cache object */
  59. struct llcache_handle {
  60.         llcache_object *object;         /**< Pointer to associated object */
  61.  
  62.         llcache_handle_callback cb;     /**< Client callback */
  63.         void *pw;                       /**< Client data */
  64.  
  65.         llcache_fetch_state state;      /**< Last known state of object fetch */
  66.         size_t bytes;                   /**< Last reported byte count */
  67. };
  68.  
  69. /** Low-level cache object user record */
  70. typedef struct llcache_object_user {
  71.         llcache_handle *handle;         /**< Handle data for client */
  72.  
  73.         bool iterator_target;           /**< This is the an iterator target */
  74.         bool queued_for_delete;         /**< This user is queued for deletion */
  75.  
  76.         struct llcache_object_user *prev;       /**< Previous in list */
  77.         struct llcache_object_user *next;       /**< Next in list */
  78. } llcache_object_user;
  79.  
  80. /** Low-level cache object fetch context */
  81. typedef struct {
  82.         uint32_t flags;                 /**< Fetch flags */
  83.         nsurl *referer;                 /**< Referring URL, or NULL if none */
  84.         llcache_post_data *post;        /**< POST data, or NULL for GET */     
  85.  
  86.         struct fetch *fetch;            /**< Fetch handle for this object */
  87.  
  88.         llcache_fetch_state state;      /**< Current state of object fetch */
  89.  
  90.         uint32_t redirect_count;        /**< Count of redirects followed */
  91.  
  92.         bool tried_with_auth;           /**< Whether we've tried with auth */
  93.  
  94.         bool tried_with_tls_downgrade;  /**< Whether we've tried TLS <= 1.0 */
  95.  
  96.         bool outstanding_query;         /**< Waiting for a query response */
  97. } llcache_fetch_ctx;
  98.  
  99. typedef enum {
  100.         LLCACHE_VALIDATE_FRESH,         /**< Only revalidate if not fresh */
  101.         LLCACHE_VALIDATE_ALWAYS,        /**< Always revalidate */
  102.         LLCACHE_VALIDATE_ONCE           /**< Revalidate once only */
  103. } llcache_validate;
  104.  
  105. /** Cache control data */
  106. typedef struct {
  107.         time_t req_time;        /**< Time of request */
  108.         time_t res_time;        /**< Time of response */
  109.         time_t date;            /**< Date: response header */
  110.         time_t expires;         /**< Expires: response header */
  111. #define INVALID_AGE -1
  112.         int age;                /**< Age: response header */
  113.         int max_age;            /**< Max-Age Cache-control parameter */
  114.         llcache_validate no_cache;      /**< No-Cache Cache-control parameter */
  115.         char *etag;             /**< Etag: response header */
  116.         time_t last_modified;   /**< Last-Modified: response header */
  117. } llcache_cache_control;
  118.  
  119. /** Representation of a fetch header */
  120. typedef struct {
  121.         char *name;             /**< Header name */
  122.         char *value;            /**< Header value */
  123. } llcache_header;
  124.  
  125. /** Low-level cache object */
  126. /** \todo Consider whether a list is a sane container */
  127. struct llcache_object {
  128.         llcache_object *prev;           /**< Previous in list */
  129.         llcache_object *next;           /**< Next in list */
  130.  
  131.         nsurl *url;                     /**< Post-redirect URL for object */
  132.         bool has_query;                 /**< URL has a query segment */
  133.  
  134.         /** \todo We need a generic dynamic buffer object */
  135.         uint8_t *source_data;           /**< Source data for object */
  136.         size_t source_len;              /**< Byte length of source data */
  137.         size_t source_alloc;            /**< Allocated size of source buffer */
  138.  
  139.         llcache_object_user *users;     /**< List of users */
  140.  
  141.         llcache_fetch_ctx fetch;        /**< Fetch context for object */
  142.  
  143.         llcache_cache_control cache;    /**< Cache control data for object */
  144.         llcache_object *candidate;      /**< Object to use, if fetch determines
  145.                                          * that it is still fresh */
  146.         uint32_t candidate_count;       /**< Count of objects this is a
  147.                                          * candidate for */
  148.  
  149.         llcache_header *headers;        /**< Fetch headers */
  150.         size_t num_headers;             /**< Number of fetch headers */
  151. };
  152.  
  153. struct llcache_s {
  154.         /** Handler for fetch-related queries */
  155.         llcache_query_callback query_cb;
  156.  
  157.         /** Data for fetch-related query handler */
  158.         void *query_cb_pw;
  159.  
  160.         /** Head of the low-level cached object list */
  161.         llcache_object *cached_objects;
  162.  
  163.         /** Head of the low-level uncached object list */
  164.         llcache_object *uncached_objects;
  165.  
  166.         uint32_t limit;
  167. };
  168.  
  169. /** low level cache state */
  170. static struct llcache_s *llcache = NULL;
  171.  
  172. /* Static lwc_strings */
  173. static lwc_string *llcache_file_lwc;
  174. static lwc_string *llcache_about_lwc;
  175. static lwc_string *llcache_resource_lwc;
  176.  
  177. /* forward referenced callback function */
  178. static void llcache_fetch_callback(const fetch_msg *msg, void *p);
  179.  
  180.  
  181. /******************************************************************************
  182.  * Low-level cache internals                                                  *
  183.  ******************************************************************************/
  184.  
  185. /**
  186.  * Create a new object user
  187.  *
  188.  * \param cb    Callback routine
  189.  * \param pw    Private data for callback
  190.  * \param user  Pointer to location to receive result
  191.  * \return NSERROR_OK on success, appropriate error otherwise
  192.  */
  193. static nserror llcache_object_user_new(llcache_handle_callback cb, void *pw,
  194.                 llcache_object_user **user)
  195. {
  196.         llcache_handle *h;
  197.         llcache_object_user *u;
  198.  
  199.         h = calloc(1, sizeof(llcache_handle));
  200.         if (h == NULL)
  201.                 return NSERROR_NOMEM;
  202.  
  203.         u = calloc(1, sizeof(llcache_object_user));
  204.         if (u == NULL) {
  205.                 free(h);
  206.                 return NSERROR_NOMEM;
  207.         }
  208.  
  209.         h->cb = cb;
  210.         h->pw = pw;
  211.  
  212.         u->handle = h;
  213.  
  214. #ifdef LLCACHE_TRACE
  215.         LOG(("Created user %p (%p, %p, %p)", u, h, (void *) cb, pw));
  216. #endif
  217.  
  218.         *user = u;
  219.  
  220.         return NSERROR_OK;
  221. }
  222.  
  223. /**
  224.  * Destroy an object user
  225.  *
  226.  * \param user  User to destroy
  227.  * \return NSERROR_OK on success, appropriate error otherwise
  228.  *
  229.  * \pre User is not attached to an object
  230.  */
  231. static nserror llcache_object_user_destroy(llcache_object_user *user)
  232. {
  233. #ifdef LLCACHE_TRACE
  234.         LOG(("Destroyed user %p", user));
  235. #endif
  236.        
  237.         assert(user->next == NULL);
  238.         assert(user->prev == NULL);
  239.        
  240.         if (user->handle != NULL)
  241.                 free(user->handle);
  242.  
  243.         free(user);
  244.  
  245.         return NSERROR_OK;
  246. }
  247.  
  248. /**
  249.  * Remove a user from a low-level cache object
  250.  *
  251.  * \param object  Object to remove user from
  252.  * \param user    User to remove
  253.  * \return NSERROR_OK.
  254.  */
  255. static nserror llcache_object_remove_user(llcache_object *object,
  256.                 llcache_object_user *user)
  257. {
  258.         assert(user != NULL);
  259.         assert(object != NULL);
  260.         assert(object->users != NULL);
  261.         assert(user->handle == NULL || user->handle->object == object);
  262.         assert((user->prev != NULL) || (object->users == user));
  263.        
  264.         if (user == object->users)
  265.                 object->users = user->next;
  266.         else
  267.                 user->prev->next = user->next;
  268.  
  269.         if (user->next != NULL)
  270.                 user->next->prev = user->prev;
  271.        
  272.         user->next = user->prev = NULL;
  273.        
  274. #ifdef LLCACHE_TRACE
  275.         LOG(("Removing user %p from %p", user, object));
  276. #endif
  277.  
  278.         return NSERROR_OK;
  279. }
  280.  
  281. /**
  282.  * Iterate the users of an object, calling their callbacks.
  283.  *
  284.  * \param object        The object to iterate
  285.  * \param event         The event to pass to the callback.
  286.  * \return NSERROR_OK on success, appropriate error otherwise.
  287.  */
  288. static nserror llcache_send_event_to_users(llcache_object *object,
  289.                                            llcache_event *event)
  290. {
  291.         nserror error = NSERROR_OK;
  292.         llcache_object_user *user, *next_user;
  293.        
  294.         user = object->users;
  295.         while (user != NULL) {
  296.                 user->iterator_target = true;
  297.  
  298.                 error = user->handle->cb(user->handle, event,
  299.                                         user->handle->pw);
  300.  
  301.                 next_user = user->next;
  302.  
  303.                 user->iterator_target = false;
  304.  
  305.                 if (user->queued_for_delete) {
  306.                         llcache_object_remove_user(object, user);
  307.                         llcache_object_user_destroy(user);
  308.                 }
  309.  
  310.                 if (error != NSERROR_OK)
  311.                         break;
  312.  
  313.                 user = next_user;
  314.         }
  315.        
  316.         return error;
  317. }
  318.  
  319. /**
  320.  * Create a new low-level cache object
  321.  *
  322.  * \param url     URL of object to create
  323.  * \param result  Pointer to location to receive result
  324.  * \return NSERROR_OK on success, appropriate error otherwise
  325.  */
  326. static nserror llcache_object_new(nsurl *url, llcache_object **result)
  327. {
  328.         llcache_object *obj = calloc(1, sizeof(llcache_object));
  329.         if (obj == NULL)
  330.                 return NSERROR_NOMEM;
  331.  
  332. #ifdef LLCACHE_TRACE
  333.         LOG(("Created object %p (%s)", obj, nsurl_access(url)));
  334. #endif
  335.  
  336.         obj->url = nsurl_ref(url);
  337.  
  338.         *result = obj;
  339.  
  340.         return NSERROR_OK;
  341. }
  342.  
  343. /**
  344.  * Clone a POST data object
  345.  *
  346.  * \param orig   Object to clone
  347.  * \param clone  Pointer to location to receive clone
  348.  * \return NSERROR_OK on success, appropriate error otherwise
  349.  */
  350. static nserror llcache_post_data_clone(const llcache_post_data *orig,
  351.                 llcache_post_data **clone)
  352. {
  353.         llcache_post_data *post_clone;
  354.  
  355.         post_clone = calloc(1, sizeof(llcache_post_data));
  356.         if (post_clone == NULL)
  357.                 return NSERROR_NOMEM;
  358.  
  359.         post_clone->type = orig->type;
  360.  
  361.         /* Deep-copy the type-specific data */
  362.         if (orig->type == LLCACHE_POST_URL_ENCODED) {
  363.                 post_clone->data.urlenc = strdup(orig->data.urlenc);
  364.                 if (post_clone->data.urlenc == NULL) {
  365.                         free(post_clone);
  366.  
  367.                         return NSERROR_NOMEM;
  368.                 }
  369.         } else {
  370.                 post_clone->data.multipart = fetch_multipart_data_clone(
  371.                                 orig->data.multipart);
  372.                 if (post_clone->data.multipart == NULL) {
  373.                         free(post_clone);
  374.  
  375.                         return NSERROR_NOMEM;
  376.                 }
  377.         }
  378.  
  379.         *clone = post_clone;
  380.  
  381.         return NSERROR_OK;
  382. }
  383.  
  384. /**
  385.  * Split a fetch header into name and value
  386.  *
  387.  * \param data   Header string
  388.  * \param len    Byte length of header
  389.  * \param name   Pointer to location to receive header name
  390.  * \param value  Pointer to location to receive header value
  391.  * \return NSERROR_OK on success, appropriate error otherwise
  392.  */
  393. static nserror llcache_fetch_split_header(const uint8_t *data, size_t len,
  394.                 char **name, char **value)
  395. {
  396.         char *n, *v;
  397.         const uint8_t *colon;
  398.  
  399.         /* Find colon */
  400.         colon = (const uint8_t *) strchr((const char *) data, ':');
  401.         if (colon == NULL) {
  402.                 /* Failed, assume a key with no value */
  403.                 n = strdup((const char *) data);
  404.                 if (n == NULL)
  405.                         return NSERROR_NOMEM;
  406.  
  407.                 v = strdup("");
  408.                 if (v == NULL) {
  409.                         free(n);
  410.                         return NSERROR_NOMEM;
  411.                 }
  412.         } else {
  413.                 /* Split header into name & value */
  414.  
  415.                 /* Strip leading whitespace from name */
  416.                 while (data[0] == ' ' || data[0] == '\t' ||
  417.                                 data[0] == '\r' || data[0] == '\n') {
  418.                         data++;
  419.                 }
  420.  
  421.                 /* Strip trailing whitespace from name */
  422.                 while (colon > data && (colon[-1] == ' ' ||
  423.                                 colon[-1] == '\t' || colon[-1] == '\r' ||
  424.                                 colon[-1] == '\n'))
  425.                         colon--;
  426.  
  427.                 n = strndup((const char *) data, colon - data);
  428.                 if (n == NULL)
  429.                         return NSERROR_NOMEM;
  430.  
  431.                 /* Find colon again */
  432.                 while (*colon != ':') {
  433.                         colon++;
  434.                 }
  435.  
  436.                 /* Skip over colon and any subsequent whitespace */
  437.                 do {
  438.                         colon++;
  439.                 } while (*colon == ' ' || *colon == '\t' ||
  440.                                 *colon == '\r' || *colon == '\n');
  441.  
  442.                 /* Strip trailing whitespace from value */
  443.                 while (len > 0 && (data[len - 1] == ' ' ||
  444.                                 data[len - 1] == '\t' ||
  445.                                 data[len - 1] == '\r' ||
  446.                                 data[len - 1] == '\n')) {
  447.                         len--;
  448.                 }
  449.  
  450.                 v = strndup((const char *) colon, len - (colon - data));
  451.                 if (v == NULL) {
  452.                         free(n);
  453.                         return NSERROR_NOMEM;
  454.                 }
  455.         }
  456.  
  457.         *name = n;
  458.         *value = v;
  459.  
  460.         return NSERROR_OK;
  461. }
  462.  
  463. /**
  464.  * Parse a fetch header
  465.  *
  466.  * \param object  Object to parse header for
  467.  * \param data    Header string
  468.  * \param len     Byte length of header
  469.  * \param name    Pointer to location to receive header name
  470.  * \param value   Pointer to location to receive header value
  471.  * \return NSERROR_OK on success, appropriate error otherwise
  472.  *
  473.  * \note This function also has the side-effect of updating
  474.  *       the cache control data for the object if an interesting
  475.  *       header is encountered
  476.  */
  477. static nserror llcache_fetch_parse_header(llcache_object *object,
  478.                 const uint8_t *data, size_t len, char **name, char **value)
  479. {
  480.         nserror error;
  481.  
  482.         /* Set fetch response time if not already set */
  483.         if (object->cache.res_time == 0)
  484.                 object->cache.res_time = time(NULL);
  485.  
  486.         /* Decompose header into name-value pair */
  487.         error = llcache_fetch_split_header(data, len, name, value);
  488.         if (error != NSERROR_OK)
  489.                 return error;
  490.  
  491.         /* Parse cache headers to populate cache control data */
  492. #define SKIP_ST(p) while (*p != '\0' && (*p == ' ' || *p == '\t')) p++
  493.  
  494.         if (5 < len && strcasecmp(*name, "Date") == 0) {
  495.                 /* extract Date header */
  496.                 /* TODO: object->cache.date = curl_getdate(*value, NULL); */
  497.           object->cache.date = (time_t) 12341234;
  498.  
  499.         } else if (4 < len && strcasecmp(*name, "Age") == 0) {
  500.                 /* extract Age header */
  501.                 if ('0' <= **value && **value <= '9')
  502.                         object->cache.age = atoi(*value);
  503.         } else if (8 < len && strcasecmp(*name, "Expires") == 0) {
  504.                 /* extract Expires header */
  505.         /* TODO: object->cache.expires = curl_getdate(*value, NULL); */
  506.                 object->cache.expires =  (time_t) 123412399;
  507.         } else if (14 < len && strcasecmp(*name, "Cache-Control") == 0) {
  508.                 /* extract and parse Cache-Control header */
  509.                 const char *start = *value;
  510.                 const char *comma = *value;
  511.  
  512.                 while (*comma != '\0') {
  513.                         while (*comma != '\0' && *comma != ',')
  514.                                 comma++;
  515.  
  516.                         if (8 < comma - start && (strncasecmp(start,
  517.                                         "no-cache", 8) == 0 ||
  518.                                         strncasecmp(start, "no-store", 8) == 0))
  519.                                 /* When we get a disk cache we should
  520.                                  * distinguish between these two */
  521.                                 object->cache.no_cache = LLCACHE_VALIDATE_ALWAYS;
  522.                         else if (7 < comma - start &&
  523.                                         strncasecmp(start, "max-age", 7) == 0) {
  524.                                 /* Find '=' */
  525.                                 while (start < comma && *start != '=')
  526.                                         start++;
  527.  
  528.                                 /* Skip over it */
  529.                                 start++;
  530.  
  531.                                 /* Skip whitespace */
  532.                                 SKIP_ST(start);
  533.  
  534.                                 if (start < comma)
  535.                                         object->cache.max_age = atoi(start);
  536.                         }
  537.  
  538.                         if (*comma != '\0') {
  539.                                 /* Skip past comma */
  540.                                 comma++;
  541.                                 /* Skip whitespace */
  542.                                 SKIP_ST(comma);
  543.                         }
  544.  
  545.                         /* Set start for next token */
  546.                         start = comma;
  547.                 }
  548.         } else if (5 < len && strcasecmp(*name, "ETag") == 0) {
  549.                 /* extract ETag header */
  550.                 free(object->cache.etag);
  551.                 object->cache.etag = strdup(*value);
  552.                 if (object->cache.etag == NULL)
  553.                         return NSERROR_NOMEM;
  554.         } else if (14 < len && strcasecmp(*name, "Last-Modified") == 0) {
  555.                 /* extract Last-Modified header */
  556.           /* TODO object->cache.last_modified = curl_getdate(*value, NULL); */
  557.           object->cache.last_modified = (time_t) 12341230;
  558.         }
  559.  
  560. #undef SKIP_ST
  561.  
  562.         return NSERROR_OK;     
  563. }
  564.  
  565. /* Destroy headers */
  566. static inline void llcache_destroy_headers(llcache_object *object)
  567. {
  568.         while (object->num_headers > 0) {
  569.                 object->num_headers--;
  570.  
  571.                 free(object->headers[object->num_headers].name);
  572.                 free(object->headers[object->num_headers].value);
  573.         }
  574.         free(object->headers);
  575.         object->headers = NULL;
  576. }
  577.  
  578. /* Invalidate cache control data */
  579. static inline void llcache_invalidate_cache_control_data(llcache_object *object)
  580. {
  581.         free(object->cache.etag);
  582.         memset(&(object->cache), 0, sizeof(llcache_cache_control));
  583.  
  584.         object->cache.age = INVALID_AGE;
  585.         object->cache.max_age = INVALID_AGE;
  586. }
  587.  
  588. /**
  589.  * Process a fetch header
  590.  *
  591.  * \param object  Object being fetched
  592.  * \param data    Header string
  593.  * \param len     Byte length of header
  594.  * \return NSERROR_OK on success, appropriate error otherwise
  595.  */
  596. static nserror llcache_fetch_process_header(llcache_object *object,
  597.                 const uint8_t *data, size_t len)
  598. {
  599.         nserror error;
  600.         char *name, *value;
  601.         llcache_header *temp;
  602.  
  603.         /* The headers for multiple HTTP responses may be delivered to us if
  604.          * the fetch layer receives a 401 response for which it has
  605.          * authentication credentials. This will result in a silent re-request
  606.          * after which we'll receive the actual response headers for the
  607.          * object we want to fetch (assuming that the credentials were correct
  608.          * of course)
  609.          *
  610.          * Therefore, if the header is an HTTP response start marker, then we
  611.          * must discard any headers we've read so far, reset the cache data
  612.          * that we might have computed, and start again.
  613.          */
  614.         /** \todo Properly parse the response line */
  615.         if (strncmp((const char *) data, "HTTP/", SLEN("HTTP/")) == 0) {
  616.                 time_t req_time = object->cache.req_time;
  617.  
  618.                 llcache_invalidate_cache_control_data(object);
  619.  
  620.                 /* Restore request time, so we compute object's age correctly */
  621.                 object->cache.req_time = req_time;
  622.  
  623.                 llcache_destroy_headers(object);
  624.         }
  625.  
  626.         error = llcache_fetch_parse_header(object, data, len, &name, &value);
  627.         if (error != NSERROR_OK)
  628.                 return error;
  629.  
  630.         /* Append header data to the object's headers array */
  631.         temp = realloc(object->headers, (object->num_headers + 1) *
  632.                         sizeof(llcache_header));
  633.         if (temp == NULL) {
  634.                 free(name);
  635.                 free(value);
  636.                 return NSERROR_NOMEM;
  637.         }
  638.  
  639.         object->headers = temp;
  640.  
  641.         object->headers[object->num_headers].name = name;
  642.         object->headers[object->num_headers].value = value;
  643.  
  644.         object->num_headers++;
  645.  
  646.         return NSERROR_OK;
  647. }
  648.  
  649. /**
  650.  * (Re)fetch an object
  651.  *
  652.  * \param object  Object to refetch
  653.  * \return NSERROR_OK on success, appropriate error otherwise
  654.  *
  655.  * \pre The fetch parameters in object->fetch must be populated
  656.  */
  657. static nserror llcache_object_refetch(llcache_object *object)
  658. {
  659.         const char *urlenc = NULL;
  660.         struct fetch_multipart_data *multipart = NULL;
  661.         char **headers = NULL;
  662.         int header_idx = 0;
  663.  
  664.         if (object->fetch.post != NULL) {
  665.                 if (object->fetch.post->type == LLCACHE_POST_URL_ENCODED)
  666.                         urlenc = object->fetch.post->data.urlenc;
  667.                 else
  668.                         multipart = object->fetch.post->data.multipart;
  669.         }
  670.  
  671.         /* Generate cache-control headers */
  672.         headers = malloc(3 * sizeof(char *));
  673.         if (headers == NULL)
  674.                 return NSERROR_NOMEM;
  675.  
  676.         if (object->cache.etag != NULL) {
  677.                 const size_t len = SLEN("If-None-Match: ") +
  678.                                 strlen(object->cache.etag) + 1;
  679.  
  680.                 headers[header_idx] = malloc(len);
  681.                 if (headers[header_idx] == NULL) {
  682.                         free(headers);
  683.                         return NSERROR_NOMEM;
  684.                 }
  685.  
  686.                 snprintf(headers[header_idx], len, "If-None-Match: %s",
  687.                                 object->cache.etag);
  688.  
  689.                 header_idx++;
  690.         }
  691.         if (object->cache.date != 0) {
  692.                 /* Maximum length of an RFC 1123 date is 29 bytes */
  693.                 const size_t len = SLEN("If-Modified-Since: ") + 29 + 1;
  694.  
  695.                 headers[header_idx] = malloc(len);
  696.                 if (headers[header_idx] == NULL) {
  697.                         while (--header_idx >= 0)
  698.                                 free(headers[header_idx]);
  699.                         free(headers);
  700.                         return NSERROR_NOMEM;
  701.                 }
  702.  
  703.                 snprintf(headers[header_idx], len, "If-Modified-Since: %s",
  704.                                 rfc1123_date(object->cache.date));
  705.  
  706.                 header_idx++;
  707.         }
  708.         headers[header_idx] = NULL;
  709.  
  710.         /* Reset cache control data */
  711.         llcache_invalidate_cache_control_data(object);
  712.         object->cache.req_time = time(NULL);
  713.  
  714.         /* Reset fetch state */
  715.         object->fetch.state = LLCACHE_FETCH_INIT;
  716.  
  717. #ifdef LLCACHE_TRACE
  718.         LOG(("Refetching %p", object));
  719. #endif
  720.  
  721.         /* Kick off fetch */
  722.         object->fetch.fetch = fetch_start(object->url, object->fetch.referer,
  723.                         llcache_fetch_callback, object,
  724.                         object->fetch.flags & LLCACHE_RETRIEVE_NO_ERROR_PAGES,
  725.                         urlenc, multipart,
  726.                         object->fetch.flags & LLCACHE_RETRIEVE_VERIFIABLE,
  727.                         object->fetch.tried_with_tls_downgrade,
  728.                         (const char **) headers);
  729.  
  730.         /* Clean up cache-control headers */
  731.         while (--header_idx >= 0)
  732.                 free(headers[header_idx]);
  733.         free(headers);
  734.  
  735.         /* Did we succeed in creating a fetch? */
  736.         if (object->fetch.fetch == NULL)
  737.                 return NSERROR_NOMEM;
  738.  
  739.         return NSERROR_OK;
  740. }
  741.  
  742. /**
  743.  * Kick-off a fetch for an object
  744.  *
  745.  * \param object          Object to fetch
  746.  * \param flags           Fetch flags
  747.  * \param referer         Referring URL, or NULL for none
  748.  * \param post            POST data, or NULL for GET
  749.  * \param redirect_count  Number of redirects followed so far
  750.  * \return NSERROR_OK on success, appropriate error otherwise
  751.  *
  752.  * \pre object::url must contain the URL to fetch
  753.  * \pre If there is a freshness validation candidate,
  754.  *      object::candidate and object::cache must be filled in
  755.  * \pre There must not be a fetch in progress for \a object
  756.  */
  757. static nserror llcache_object_fetch(llcache_object *object, uint32_t flags,
  758.                 nsurl *referer, const llcache_post_data *post,
  759.                 uint32_t redirect_count)
  760. {
  761.         nserror error;
  762.         nsurl *referer_clone = NULL;
  763.         llcache_post_data *post_clone = NULL;
  764.  
  765. #ifdef LLCACHE_TRACE
  766.         LOG(("Starting fetch for %p", object));
  767. #endif
  768.  
  769.         if (post != NULL) {
  770.                 error = llcache_post_data_clone(post, &post_clone);
  771.                 if (error != NSERROR_OK)
  772.                         return error;
  773.         }
  774.  
  775.         if (referer != NULL)
  776.                 referer_clone = nsurl_ref(referer);
  777.  
  778.         object->fetch.flags = flags;
  779.         object->fetch.referer = referer_clone;
  780.         object->fetch.post = post_clone;
  781.         object->fetch.redirect_count = redirect_count;
  782.  
  783.         return llcache_object_refetch(object);
  784. }
  785.  
  786. /**
  787.  * Destroy a low-level cache object
  788.  *
  789.  * \param object  Object to destroy
  790.  * \return NSERROR_OK on success, appropriate error otherwise
  791.  *
  792.  * \pre Object is detached from cache list
  793.  * \pre Object has no users
  794.  * \pre Object is not a candidate (i.e. object::candidate_count == 0)
  795.  */
  796. static nserror llcache_object_destroy(llcache_object *object)
  797. {
  798.         size_t i;
  799.  
  800. #ifdef LLCACHE_TRACE
  801.         LOG(("Destroying object %p", object));
  802. #endif
  803.  
  804.         nsurl_unref(object->url);
  805.         free(object->source_data);
  806.  
  807.         if (object->fetch.fetch != NULL) {
  808.                 fetch_abort(object->fetch.fetch);
  809.                 object->fetch.fetch = NULL;
  810.         }
  811.  
  812.         if (object->fetch.referer != NULL)
  813.                 nsurl_unref(object->fetch.referer);
  814.  
  815.         if (object->fetch.post != NULL) {
  816.                 if (object->fetch.post->type == LLCACHE_POST_URL_ENCODED) {
  817.                         free(object->fetch.post->data.urlenc);
  818.                 } else {
  819.                         fetch_multipart_data_destroy(
  820.                                         object->fetch.post->data.multipart);
  821.                 }
  822.  
  823.                 free(object->fetch.post);
  824.         }
  825.  
  826.         free(object->cache.etag);
  827.  
  828.         for (i = 0; i < object->num_headers; i++) {
  829.                 free(object->headers[i].name);
  830.                 free(object->headers[i].value);
  831.         }
  832.         free(object->headers);
  833.  
  834.         free(object);
  835.  
  836.         return NSERROR_OK;
  837. }
  838.  
  839. /**
  840.  * Add a low-level cache object to a cache list
  841.  *
  842.  * \param object  Object to add
  843.  * \param list    List to add to
  844.  * \return NSERROR_OK
  845.  */
  846. static nserror llcache_object_add_to_list(llcache_object *object,
  847.                 llcache_object **list)
  848. {
  849.         object->prev = NULL;
  850.         object->next = *list;
  851.  
  852.         if (*list != NULL)
  853.                 (*list)->prev = object;
  854.         *list = object;
  855.  
  856.         return NSERROR_OK;
  857. }
  858.  
  859. /**
  860.  * Determine the remaining lifetime of a cache object using the
  861.  *
  862.  * \param object  Object to consider
  863.  * \return True if object is still fresh, false otherwise
  864.  */
  865. static int
  866. llcache_object_rfc2616_remaining_lifetime(const llcache_cache_control *cd)
  867. {
  868.         int current_age, freshness_lifetime;
  869.         time_t now = time(NULL);
  870.  
  871.         /* Calculate staleness of cached object as per RFC 2616 13.2.3/13.2.4 */
  872.         current_age = max(0, (cd->res_time - cd->date));
  873.         current_age = max(current_age, (cd->age == INVALID_AGE) ? 0 : cd->age);
  874.         current_age += cd->res_time - cd->req_time + now - cd->res_time;
  875.  
  876.         /* Determine freshness lifetime of this object */
  877.         if (cd->max_age != INVALID_AGE)
  878.                 freshness_lifetime = cd->max_age;
  879.         else if (cd->expires != 0)
  880.                 freshness_lifetime = cd->expires - cd->date;
  881.         else if (cd->last_modified != 0)
  882.                 freshness_lifetime = (now - cd->last_modified) / 10;
  883.         else
  884.                 freshness_lifetime = 0;
  885.  
  886. #ifdef LLCACHE_TRACE
  887.         LOG(("%d:%d", freshness_lifetime, current_age));
  888. #endif
  889.  
  890.         if ((cd->no_cache == LLCACHE_VALIDATE_FRESH) &&
  891.             (freshness_lifetime > current_age)) {
  892.                 /* object was not forbidden from being returned from
  893.                  * the cache unvalidated (i.e. the response contained
  894.                  * a no-cache directive)
  895.                  *
  896.                  * The object current age is within the freshness lifetime.
  897.                  */
  898.                 return freshness_lifetime - current_age;
  899.         }
  900.  
  901.         return 0; /* object has no remaining lifetime */
  902. }
  903.  
  904. /**
  905.  * Determine if an object is still fresh
  906.  *
  907.  * \param object  Object to consider
  908.  * \return True if object is still fresh, false otherwise
  909.  */
  910. static bool llcache_object_is_fresh(const llcache_object *object)
  911. {
  912.         int remaining_lifetime;
  913.         const llcache_cache_control *cd = &object->cache;
  914.  
  915.         remaining_lifetime = llcache_object_rfc2616_remaining_lifetime(cd);
  916.  
  917. #ifdef LLCACHE_TRACE
  918.         LOG(("%p: (%d > 0 || %d != %d)", object,
  919.              remaining_lifetime,
  920.              object->fetch.state, LLCACHE_FETCH_COMPLETE));
  921. #endif
  922.  
  923.         /* The object is fresh if:
  924.          * - it was not forbidden from being returned from the cache
  925.          *   unvalidated.
  926.          *
  927.          * - it has remaining lifetime or still being fetched.
  928.          */
  929.         return ((cd->no_cache == LLCACHE_VALIDATE_FRESH) &&
  930.                 ((remaining_lifetime > 0) ||
  931.                  (object->fetch.state != LLCACHE_FETCH_COMPLETE)));
  932. }
  933.  
  934. /**
  935.  * Clone an object's cache data
  936.  *
  937.  * \param source       Source object containing cache data to clone
  938.  * \param destination  Destination object to clone cache data into
  939.  * \param deep         Whether to deep-copy the data or not
  940.  * \return NSERROR_OK on success, appropriate error otherwise
  941.  *
  942.  * \post If \a deep is false, then any pointers in \a source will be set to NULL
  943.  */
  944. static nserror llcache_object_clone_cache_data(llcache_object *source,
  945.                 llcache_object *destination, bool deep)
  946. {
  947.         /* ETag must be first, as it can fail when deep cloning */
  948.         if (source->cache.etag != NULL) {
  949.                 char *etag = source->cache.etag;
  950.  
  951.                 if (deep) {
  952.                         /* Copy the etag */
  953.                         etag = strdup(source->cache.etag);
  954.                         if (etag == NULL)
  955.                                 return NSERROR_NOMEM;
  956.                 } else {
  957.                         /* Destination takes ownership */
  958.                         source->cache.etag = NULL;
  959.                 }
  960.  
  961.                 if (destination->cache.etag != NULL)
  962.                         free(destination->cache.etag);
  963.  
  964.                 destination->cache.etag = etag;
  965.         }
  966.  
  967.         destination->cache.req_time = source->cache.req_time;
  968.         destination->cache.res_time = source->cache.res_time;
  969.  
  970.         if (source->cache.date != 0)
  971.                 destination->cache.date = source->cache.date;
  972.  
  973.         if (source->cache.expires != 0)
  974.                 destination->cache.expires = source->cache.expires;
  975.  
  976.         if (source->cache.age != INVALID_AGE)
  977.                 destination->cache.age = source->cache.age;
  978.  
  979.         if (source->cache.max_age != INVALID_AGE)
  980.                 destination->cache.max_age = source->cache.max_age;
  981.  
  982.         if (source->cache.no_cache != LLCACHE_VALIDATE_FRESH)
  983.                 destination->cache.no_cache = source->cache.no_cache;
  984.        
  985.         if (source->cache.last_modified != 0)
  986.                 destination->cache.last_modified = source->cache.last_modified;
  987.  
  988.         return NSERROR_OK;
  989. }
  990.  
  991. /**
  992.  * Retrieve a potentially cached object
  993.  *
  994.  * \param url             URL of object to retrieve
  995.  * \param flags           Fetch flags
  996.  * \param referer         Referring URL, or NULL if none
  997.  * \param post            POST data, or NULL for a GET request
  998.  * \param redirect_count  Number of redirects followed so far
  999.  * \param result          Pointer to location to recieve retrieved object
  1000.  * \return NSERROR_OK on success, appropriate error otherwise
  1001.  */
  1002. static nserror llcache_object_retrieve_from_cache(nsurl *url, uint32_t flags,
  1003.                 nsurl *referer, const llcache_post_data *post,
  1004.                 uint32_t redirect_count, llcache_object **result)
  1005. {
  1006.         nserror error;
  1007.         llcache_object *obj, *newest = NULL;
  1008.  
  1009. #ifdef LLCACHE_TRACE
  1010.         LOG(("Searching cache for %s (%x %s %p)", url, flags, referer, post));
  1011. #endif
  1012.  
  1013.         /* Search for the most recently fetched matching object */
  1014.         for (obj = llcache->cached_objects; obj != NULL; obj = obj->next) {
  1015.  
  1016.                 if ((newest == NULL ||
  1017.                                 obj->cache.req_time > newest->cache.req_time) &&
  1018.                                 nsurl_compare(obj->url, url,
  1019.                                                 NSURL_COMPLETE) == true) {
  1020.                         newest = obj;
  1021.                 }
  1022.         }
  1023.  
  1024.         if (newest != NULL && llcache_object_is_fresh(newest)) {
  1025.                 /* Found a suitable object, and it's still fresh, so use it */
  1026.                 obj = newest;
  1027.  
  1028. #ifdef LLCACHE_TRACE
  1029.                 LOG(("Found fresh %p", obj));
  1030. #endif
  1031.  
  1032.                 /* The client needs to catch up with the object's state.
  1033.                  * This will occur the next time that llcache_poll is called.
  1034.                  */
  1035.         } else if (newest != NULL) {
  1036.                 /* Found a candidate object but it needs freshness validation */
  1037.  
  1038.                 /* Create a new object */
  1039.                 error = llcache_object_new(url, &obj);
  1040.                 if (error != NSERROR_OK)
  1041.                         return error;
  1042.  
  1043. #ifdef LLCACHE_TRACE
  1044.                 LOG(("Found candidate %p (%p)", obj, newest));
  1045. #endif
  1046.  
  1047.                 /* Clone candidate's cache data */
  1048.                 error = llcache_object_clone_cache_data(newest, obj, true);
  1049.                 if (error != NSERROR_OK) {
  1050.                         llcache_object_destroy(obj);
  1051.                         return error;
  1052.                 }                      
  1053.  
  1054.                 /* Record candidate, so we can fall back if it is still fresh */
  1055.                 newest->candidate_count++;
  1056.                 obj->candidate = newest;
  1057.  
  1058.                 /* Attempt to kick-off fetch */
  1059.                 error = llcache_object_fetch(obj, flags, referer, post,
  1060.                                 redirect_count);
  1061.                 if (error != NSERROR_OK) {
  1062.                         newest->candidate_count--;
  1063.                         llcache_object_destroy(obj);
  1064.                         return error;
  1065.                 }
  1066.  
  1067.                 /* Add new object to cache */
  1068.                 llcache_object_add_to_list(obj, &llcache->cached_objects);
  1069.         } else {
  1070.                 /* No object found; create a new one */
  1071.                 /* Create new object */
  1072.                 error = llcache_object_new(url, &obj);
  1073.                 if (error != NSERROR_OK)
  1074.                         return error;
  1075.  
  1076. #ifdef LLCACHE_TRACE
  1077.                 LOG(("Not found %p", obj));
  1078. #endif
  1079.  
  1080.                 /* Attempt to kick-off fetch */
  1081.                 error = llcache_object_fetch(obj, flags, referer, post,
  1082.                                 redirect_count);
  1083.                 if (error != NSERROR_OK) {
  1084.                         llcache_object_destroy(obj);
  1085.                         return error;
  1086.                 }
  1087.  
  1088.                 /* Add new object to cache */
  1089.                 llcache_object_add_to_list(obj, &llcache->cached_objects);
  1090.         }
  1091.  
  1092.         *result = obj;
  1093.  
  1094.         return NSERROR_OK;
  1095. }
  1096.  
  1097. /**
  1098.  * Retrieve an object from the cache, fetching it if necessary.
  1099.  *
  1100.  * \param url             URL of object to retrieve
  1101.  * \param flags           Fetch flags
  1102.  * \param referer         Referring URL, or NULL if none
  1103.  * \param post            POST data, or NULL for a GET request
  1104.  * \param redirect_count  Number of redirects followed so far
  1105.  * \param result          Pointer to location to recieve retrieved object
  1106.  * \return NSERROR_OK on success, appropriate error otherwise
  1107.  */
  1108. static nserror llcache_object_retrieve(nsurl *url, uint32_t flags,
  1109.                 nsurl *referer, const llcache_post_data *post,
  1110.                 uint32_t redirect_count, llcache_object **result)
  1111. {
  1112.         nserror error;
  1113.         llcache_object *obj;
  1114.         bool has_query;
  1115.         nsurl *defragmented_url;
  1116.  
  1117. #ifdef LLCACHE_TRACE
  1118.         LOG(("Retrieve %s (%x, %s, %p)", url, flags, referer, post));
  1119. #endif
  1120.  
  1121.         /**
  1122.          * Caching Rules:
  1123.          *
  1124.          * 1) Forced fetches are never cached
  1125.          * 2) POST requests are never cached
  1126.          */
  1127.  
  1128.         /* Look for a query segment */
  1129.         has_query = nsurl_has_component(url, NSURL_QUERY);
  1130.  
  1131.         /* Get rid of any url fragment */
  1132.         if (nsurl_has_component(url, NSURL_FRAGMENT)) {
  1133.                 error = nsurl_defragment(url, &defragmented_url);
  1134.                 if (error != NSERROR_OK)
  1135.                         return error;
  1136.         } else {
  1137.                 defragmented_url = nsurl_ref(url);
  1138.         }
  1139.  
  1140.         if (flags & LLCACHE_RETRIEVE_FORCE_FETCH || post != NULL) {
  1141.                 /* Create new object */
  1142.                 error = llcache_object_new(defragmented_url, &obj);
  1143.                 if (error != NSERROR_OK) {
  1144.                         nsurl_unref(defragmented_url);
  1145.                         return error;
  1146.                 }
  1147.  
  1148.                 /* Attempt to kick-off fetch */
  1149.                 error = llcache_object_fetch(obj, flags, referer, post,
  1150.                                 redirect_count);
  1151.                 if (error != NSERROR_OK) {
  1152.                         llcache_object_destroy(obj);
  1153.                         nsurl_unref(defragmented_url);
  1154.                         return error;
  1155.                 }
  1156.  
  1157.                 /* Add new object to uncached list */
  1158.                 llcache_object_add_to_list(obj, &llcache->uncached_objects);
  1159.         } else {
  1160.                 error = llcache_object_retrieve_from_cache(defragmented_url,
  1161.                                 flags, referer, post, redirect_count, &obj);
  1162.                 if (error != NSERROR_OK) {
  1163.                         nsurl_unref(defragmented_url);
  1164.                         return error;
  1165.                 }
  1166.  
  1167.                 /* Returned object is already in the cached list */
  1168.         }
  1169.        
  1170.         obj->has_query = has_query;
  1171.  
  1172. #ifdef LLCACHE_TRACE
  1173.         LOG(("Retrieved %p", obj));
  1174. #endif
  1175.        
  1176.         *result = obj;
  1177.        
  1178.         nsurl_unref(defragmented_url);
  1179.        
  1180.         return NSERROR_OK;
  1181. }
  1182.  
  1183. /**
  1184.  * Add a user to a low-level cache object
  1185.  *
  1186.  * \param object  Object to add user to
  1187.  * \param user    User to add
  1188.  * \return NSERROR_OK.
  1189.  */
  1190. static nserror llcache_object_add_user(llcache_object *object,
  1191.                 llcache_object_user *user)
  1192. {
  1193.         assert(user->next == NULL);
  1194.         assert(user->prev == NULL);
  1195.  
  1196.         user->handle->object = object;
  1197.  
  1198.         user->prev = NULL;
  1199.         user->next = object->users;
  1200.  
  1201.         if (object->users != NULL)
  1202.                 object->users->prev = user;
  1203.         object->users = user;
  1204.  
  1205. #ifdef LLCACHE_TRACE
  1206.         LOG(("Adding user %p to %p", user, object));
  1207. #endif
  1208.  
  1209.         return NSERROR_OK;
  1210. }
  1211.  
  1212. /**
  1213.  * Handle FETCH_REDIRECT event
  1214.  *
  1215.  * \param object       Object being redirected
  1216.  * \param target       Target of redirect (may be relative)
  1217.  * \param replacement  Pointer to location to receive replacement object
  1218.  * \return NSERROR_OK on success, appropriate error otherwise
  1219.  */
  1220. static nserror llcache_fetch_redirect(llcache_object *object, const char *target,
  1221.                 llcache_object **replacement)
  1222. {
  1223.         nserror error;
  1224.         llcache_object *dest;
  1225.         llcache_object_user *user, *next;
  1226.         const llcache_post_data *post = object->fetch.post;
  1227.         nsurl *url;
  1228.         lwc_string *scheme;
  1229.         lwc_string *object_scheme;
  1230.         bool match;
  1231.         /* Extract HTTP response code from the fetch object */
  1232.         long http_code = fetch_http_code(object->fetch.fetch);
  1233.  
  1234.         /* Abort fetch for this object */
  1235.         fetch_abort(object->fetch.fetch);
  1236.         object->fetch.fetch = NULL;
  1237.        
  1238.         /* Invalidate the cache control data */
  1239.         llcache_invalidate_cache_control_data(object);
  1240.  
  1241.         /* And mark it complete */
  1242.         object->fetch.state = LLCACHE_FETCH_COMPLETE;
  1243.        
  1244.         /* Forcibly stop redirecting if we've followed too many redirects */
  1245. #define REDIRECT_LIMIT 10
  1246.         if (object->fetch.redirect_count > REDIRECT_LIMIT) {
  1247.                 llcache_event event;
  1248.  
  1249.                 LOG(("Too many nested redirects"));
  1250.  
  1251.                 event.type = LLCACHE_EVENT_ERROR;
  1252.                 event.data.msg = messages_get("BadRedirect");
  1253.                
  1254.                 return llcache_send_event_to_users(object, &event);
  1255.         }
  1256. #undef REDIRECT_LIMIT
  1257.  
  1258.         /* Make target absolute */
  1259.         error = nsurl_join(object->url, target, &url);
  1260.         if (error != NSERROR_OK)
  1261.                 return error;
  1262.  
  1263.         /* Reject attempts to redirect from unvalidated to validated schemes
  1264.          * A "validated" scheme is one over which we have some guarantee that
  1265.          * the source is trustworthy. */
  1266.         object_scheme = nsurl_get_component(object->url, NSURL_SCHEME);
  1267.         scheme = nsurl_get_component(url, NSURL_SCHEME);
  1268.  
  1269.         /* resource: and about: are allowed to redirect anywhere */
  1270.         if ((lwc_string_isequal(object_scheme, llcache_resource_lwc,
  1271.                         &match) == lwc_error_ok && match == false) &&
  1272.             (lwc_string_isequal(object_scheme, llcache_about_lwc,
  1273.                         &match) == lwc_error_ok && match == false)) {
  1274.                 /* file, about and resource are not valid redirect targets */
  1275.                 if ((lwc_string_isequal(object_scheme, llcache_file_lwc,
  1276.                                 &match) == lwc_error_ok && match == true) ||
  1277.                     (lwc_string_isequal(object_scheme, llcache_about_lwc,
  1278.                                 &match) == lwc_error_ok && match == true) ||
  1279.                     (lwc_string_isequal(object_scheme, llcache_resource_lwc,
  1280.                                 &match) == lwc_error_ok && match == true)) {
  1281.                         lwc_string_unref(object_scheme);
  1282.                         lwc_string_unref(scheme);
  1283.                         nsurl_unref(url);
  1284.                         return NSERROR_OK;
  1285.                 }
  1286.         }
  1287.  
  1288.         lwc_string_unref(scheme);
  1289.         lwc_string_unref(object_scheme);
  1290.  
  1291.         /* Bail out if we've no way of handling this URL */
  1292.         if (fetch_can_fetch(url) == false) {
  1293.                 nsurl_unref(url);
  1294.                 return NSERROR_OK;
  1295.         }
  1296.  
  1297.         if (http_code == 301 || http_code == 302 || http_code == 303) {
  1298.                 /* 301, 302, 303 redirects are all unconditional GET requests */
  1299.                 post = NULL;
  1300.         } else if (http_code != 307 || post != NULL) {
  1301.                 /** \todo 300, 305, 307 with POST */
  1302.                 nsurl_unref(url);
  1303.                 return NSERROR_OK;
  1304.         }
  1305.  
  1306.         /* Attempt to fetch target URL */
  1307.         error = llcache_object_retrieve(url, object->fetch.flags,
  1308.                         object->fetch.referer, post,
  1309.                         object->fetch.redirect_count + 1, &dest);
  1310.  
  1311.         /* No longer require url */
  1312.         nsurl_unref(url);
  1313.  
  1314.         if (error != NSERROR_OK)
  1315.                 return error;
  1316.  
  1317.         /* Move user(s) to replacement object */
  1318.         for (user = object->users; user != NULL; user = next) {
  1319.                 next = user->next;
  1320.  
  1321.                 llcache_object_remove_user(object, user);
  1322.                 llcache_object_add_user(dest, user);
  1323.         }
  1324.  
  1325.         /* Dest is now our object */
  1326.         *replacement = dest;
  1327.  
  1328.         return NSERROR_OK;     
  1329. }
  1330.  
  1331. /**
  1332.  * Update an object's cache state
  1333.  *
  1334.  * \param object  Object to update cache for
  1335.  * \return NSERROR_OK.
  1336.  */
  1337. static nserror llcache_object_cache_update(llcache_object *object)
  1338. {
  1339.         if (object->cache.date == 0)
  1340.                 object->cache.date = time(NULL);
  1341.  
  1342.         return NSERROR_OK;
  1343. }
  1344.  
  1345. /**
  1346.  * Handle FETCH_NOTMODIFIED event
  1347.  *
  1348.  * \param object       Object to process
  1349.  * \param replacement  Pointer to location to receive replacement object
  1350.  * \return NSERROR_OK.
  1351.  */
  1352. static nserror llcache_fetch_notmodified(llcache_object *object,
  1353.                 llcache_object **replacement)
  1354. {
  1355.         /* There may be no candidate if the server erroneously responded
  1356.          * to an unconditional request with a 304 Not Modified response.
  1357.          * In this case, we simply retain the initial object, having
  1358.          * invalidated it and marked it as complete.
  1359.          */
  1360.         if (object->candidate != NULL) {
  1361.                 llcache_object_user *user, *next;
  1362.  
  1363.                 /* Move user(s) to candidate content */
  1364.                 for (user = object->users; user != NULL; user = next) {
  1365.                         next = user->next;
  1366.  
  1367.                         llcache_object_remove_user(object, user);
  1368.                         llcache_object_add_user(object->candidate, user);
  1369.                 }
  1370.  
  1371.                 /* Candidate is no longer a candidate for us */
  1372.                 object->candidate->candidate_count--;
  1373.  
  1374.                 /* Clone our cache control data into the candidate */
  1375.                 llcache_object_clone_cache_data(object, object->candidate,
  1376.                                 false);
  1377.                 /* Bring candidate's cache data up to date */
  1378.                 llcache_object_cache_update(object->candidate);
  1379.                 /* Revert no-cache to normal, if required */
  1380.                 if (object->candidate->cache.no_cache ==
  1381.                                 LLCACHE_VALIDATE_ONCE) {
  1382.                         object->candidate->cache.no_cache =
  1383.                                 LLCACHE_VALIDATE_FRESH;
  1384.                 }
  1385.  
  1386.                 /* Candidate is now our object */
  1387.                 *replacement = object->candidate;
  1388.                 object->candidate = NULL;
  1389.         } else {
  1390.                 /* There was no candidate: retain object */
  1391.                 *replacement = object;
  1392.         }
  1393.  
  1394.         /* Ensure fetch has stopped */
  1395.         fetch_abort(object->fetch.fetch);
  1396.         object->fetch.fetch = NULL;
  1397.  
  1398.         /* Invalidate our cache-control data */
  1399.         llcache_invalidate_cache_control_data(object);
  1400.  
  1401.         /* Mark it complete */
  1402.         object->fetch.state = LLCACHE_FETCH_COMPLETE;
  1403.  
  1404.         /* Old object will be flushed from the cache on the next poll */
  1405.  
  1406.         return NSERROR_OK;
  1407. }
  1408.  
  1409. /**
  1410.  * Process a chunk of fetched data
  1411.  *
  1412.  * \param object  Object being fetched
  1413.  * \param data    Data to process
  1414.  * \param len     Byte length of data
  1415.  * \return NSERROR_OK on success, appropriate error otherwise.
  1416.  */
  1417. static nserror llcache_fetch_process_data(llcache_object *object, const uint8_t *data,
  1418.                 size_t len)
  1419. {
  1420.         /* Resize source buffer if it's too small */
  1421.         if (object->source_len + len >= object->source_alloc) {
  1422.                 const size_t new_len = object->source_len + len + 64 * 1024;
  1423.                 uint8_t *temp = realloc(object->source_data, new_len);
  1424.                 if (temp == NULL)
  1425.                         return NSERROR_NOMEM;
  1426.  
  1427.                 object->source_data = temp;
  1428.                 object->source_alloc = new_len;
  1429.         }
  1430.  
  1431.         /* Append this data chunk to source buffer */
  1432.         memcpy(object->source_data + object->source_len, data, len);
  1433.         object->source_len += len;
  1434.  
  1435.         return NSERROR_OK;
  1436. }
  1437.  
  1438. /**
  1439.  * Handle a query response
  1440.  *
  1441.  * \param proceed  Whether to proceed with fetch
  1442.  * \param cbpw     Our context for query
  1443.  * \return NSERROR_OK on success, appropriate error otherwise
  1444.  */
  1445. static nserror llcache_query_handle_response(bool proceed, void *cbpw)
  1446. {
  1447.         llcache_event event;
  1448.         llcache_object *object = cbpw;
  1449.  
  1450.         object->fetch.outstanding_query = false;
  1451.  
  1452.         /* Refetch, using existing fetch parameters, if client allows us to */
  1453.         if (proceed)
  1454.                 return llcache_object_refetch(object);
  1455.  
  1456.         /* Invalidate cache-control data */
  1457.         llcache_invalidate_cache_control_data(object);
  1458.  
  1459.         /* Mark it complete */
  1460.         object->fetch.state = LLCACHE_FETCH_COMPLETE;
  1461.  
  1462.         /* Inform client(s) that object fetch failed */
  1463.         event.type = LLCACHE_EVENT_ERROR;
  1464.         /** \todo More appropriate error message */
  1465.         event.data.msg = messages_get("FetchFailed");
  1466.        
  1467.         return llcache_send_event_to_users(object, &event);
  1468. }
  1469.  
  1470. /**
  1471.  * Handle an authentication request
  1472.  *
  1473.  * \param object  Object being fetched
  1474.  * \param realm   Authentication realm
  1475.  * \return NSERROR_OK on success, appropriate error otherwise.
  1476.  */
  1477. static nserror llcache_fetch_auth(llcache_object *object, const char *realm)
  1478. {
  1479.         const char *auth;
  1480.         nserror error = NSERROR_OK;
  1481.  
  1482.         /* Abort fetch for this object */
  1483.         fetch_abort(object->fetch.fetch);
  1484.         object->fetch.fetch = NULL;
  1485.  
  1486.         /* Invalidate cache-control data */
  1487.         llcache_invalidate_cache_control_data(object);
  1488.  
  1489.         /* Destroy headers */
  1490.         llcache_destroy_headers(object);
  1491.  
  1492.         /* If there was no realm, then default to the URL */
  1493.         /** \todo If there was no WWW-Authenticate header, use response body */
  1494.         if (realm == NULL)
  1495.                 realm = nsurl_access(object->url);
  1496.  
  1497.         auth = urldb_get_auth_details(object->url, realm);
  1498.  
  1499.         if (auth == NULL || object->fetch.tried_with_auth == true) {
  1500.                 /* No authentication details, or tried what we had, so ask */
  1501.                 object->fetch.tried_with_auth = false;
  1502.  
  1503.                 if (llcache->query_cb != NULL) {
  1504.                         llcache_query query;
  1505.  
  1506.                         /* Emit query for authentication details */
  1507.                         query.type = LLCACHE_QUERY_AUTH;
  1508.                         query.url = object->url;
  1509.                         query.data.auth.realm = realm;
  1510.  
  1511.                         object->fetch.outstanding_query = true;
  1512.  
  1513.                         error = llcache->query_cb(&query, llcache->query_cb_pw,
  1514.                                         llcache_query_handle_response, object);
  1515.                 } else {
  1516.                         llcache_event event;
  1517.  
  1518.                         /* Mark object complete */
  1519.                         object->fetch.state = LLCACHE_FETCH_COMPLETE;
  1520.  
  1521.                         /* Inform client(s) that object fetch failed */
  1522.                         event.type = LLCACHE_EVENT_ERROR;
  1523.                         /** \todo More appropriate error message */
  1524.                         event.data.msg = messages_get("FetchFailed");
  1525.                
  1526.                         error = llcache_send_event_to_users(object, &event);
  1527.                 }
  1528.         } else {
  1529.                 /* Flag that we've tried to refetch with credentials, so
  1530.                  * that if the fetch fails again, we ask the user again */
  1531.                 object->fetch.tried_with_auth = true;
  1532.                 error = llcache_object_refetch(object);
  1533.         }
  1534.  
  1535.         return error;
  1536. }
  1537.  
  1538. /**
  1539.  * Handle a TLS certificate verification failure
  1540.  *
  1541.  * \param object  Object being fetched
  1542.  * \param certs   Certificate chain
  1543.  * \param num     Number of certificates in chain
  1544.  * \return NSERROR_OK on success, appropriate error otherwise
  1545.  */
  1546. static nserror llcache_fetch_cert_error(llcache_object *object,
  1547.                 const struct ssl_cert_info *certs, size_t num)
  1548. {
  1549.         nserror error = NSERROR_OK;
  1550.  
  1551.         /* Fetch has been stopped, and destroyed. Invalidate object's pointer */
  1552.         object->fetch.fetch = NULL;
  1553.  
  1554.         /* Invalidate cache-control data */
  1555.         llcache_invalidate_cache_control_data(object);
  1556.  
  1557.         if (llcache->query_cb != NULL) {
  1558.                 llcache_query query;
  1559.  
  1560.                 /* Emit query for TLS */
  1561.                 query.type = LLCACHE_QUERY_SSL;
  1562.                 query.url = object->url;
  1563.                 query.data.ssl.certs = certs;
  1564.                 query.data.ssl.num = num;
  1565.  
  1566.                 object->fetch.outstanding_query = true;
  1567.  
  1568.                 error = llcache->query_cb(&query, llcache->query_cb_pw,
  1569.                                 llcache_query_handle_response, object);
  1570.         } else {
  1571.                 llcache_event event;
  1572.  
  1573.                 /* Mark object complete */
  1574.                 object->fetch.state = LLCACHE_FETCH_COMPLETE;
  1575.  
  1576.                 /* Inform client(s) that object fetch failed */
  1577.                 event.type = LLCACHE_EVENT_ERROR;
  1578.                 /** \todo More appropriate error message */
  1579.                 event.data.msg = messages_get("FetchFailed");
  1580.                
  1581.                 error = llcache_send_event_to_users(object, &event);
  1582.         }
  1583.  
  1584.         return error;
  1585. }
  1586.  
  1587. /**
  1588.  * Handle a TLS connection setup failure
  1589.  *
  1590.  * \param object  Object being fetched
  1591.  * \return NSERROR_OK on success, appropriate error otherwise
  1592.  */
  1593. static nserror llcache_fetch_ssl_error(llcache_object *object)
  1594. {
  1595.         nserror error = NSERROR_OK;
  1596.  
  1597.         /* Fetch has been stopped, and destroyed. Invalidate object's pointer */
  1598.         object->fetch.fetch = NULL;
  1599.  
  1600.         /* Invalidate cache-control data */
  1601.         llcache_invalidate_cache_control_data(object);
  1602.  
  1603.         if (object->fetch.tried_with_tls_downgrade == true) {
  1604.                 /* Have already tried to downgrade, so give up */
  1605.                 llcache_event event;
  1606.  
  1607.                 /* Mark object complete */
  1608.                 object->fetch.state = LLCACHE_FETCH_COMPLETE;
  1609.  
  1610.                 /* Inform client(s) that object fetch failed */
  1611.                 event.type = LLCACHE_EVENT_ERROR;
  1612.                 /** \todo More appropriate error message */
  1613.                 event.data.msg = messages_get("FetchFailed");
  1614.        
  1615.                 error = llcache_send_event_to_users(object, &event);
  1616.         } else {
  1617.                 /* Flag that we've tried to downgrade, so that if the
  1618.                  * fetch fails again, we give up */
  1619.                 object->fetch.tried_with_tls_downgrade = true;
  1620.                 error = llcache_object_refetch(object);
  1621.         }
  1622.  
  1623.         return error;
  1624. }
  1625.  
  1626. /**
  1627.  * Handler for fetch events
  1628.  *
  1629.  * \param msg        Fetch event
  1630.  * \param p          Our private data
  1631.  */
  1632. static void llcache_fetch_callback(const fetch_msg *msg, void *p)
  1633. {
  1634.         nserror error = NSERROR_OK;
  1635.         llcache_object *object = p;
  1636.         llcache_event event;
  1637.         /* DBG("Inside llcache_fetch_callback\n"); */
  1638.  
  1639. #ifdef LLCACHE_TRACE
  1640.         LOG(("Fetch event %d for %p", msg->type, object));
  1641. #endif
  1642.         if(!msg)
  1643.           LOG(("msg is NULL in llcache_fetch_callback\n"));
  1644.  
  1645.         switch (msg->type) {
  1646.         case FETCH_HEADER:
  1647.           /* DBG("FETCH_HEADER in llcache\n"); */
  1648.                 /* Received a fetch header */
  1649.                 object->fetch.state = LLCACHE_FETCH_HEADERS;
  1650.  
  1651.                 error = llcache_fetch_process_header(object,
  1652.                                 msg->data.header_or_data.buf,
  1653.                                 msg->data.header_or_data.len);
  1654.                 break;
  1655.  
  1656.         /* 3xx responses */
  1657.         case FETCH_REDIRECT:
  1658.                 /* Request resulted in a redirect */
  1659.           /* DBG("FETCH_REDIRECT in llcache\n"); */
  1660.                 /* Release candidate, if any */
  1661.                 if (object->candidate != NULL) {
  1662.                         object->candidate->candidate_count--;
  1663.                         object->candidate = NULL;
  1664.                 }
  1665.  
  1666.                 error = llcache_fetch_redirect(object,
  1667.                                 msg->data.redirect, &object);
  1668.                 break;
  1669.         case FETCH_NOTMODIFIED:
  1670.                 /* Conditional request determined that cached object is fresh */
  1671.                   /* DBG("FETCH_NOTMODIFIED in llcache\n"); */
  1672.                 error = llcache_fetch_notmodified(object, &object);
  1673.                 break;
  1674.  
  1675.         /* Normal 2xx state machine */
  1676.         case FETCH_DATA:
  1677.                   /* DBG("FETCH_DATA in llcache\n"); */
  1678.                 /* Received some data */
  1679.                 if (object->fetch.state != LLCACHE_FETCH_DATA) {
  1680.                         /* On entry into this state, check if we need to
  1681.                          * invalidate the cache control data. We are guaranteed
  1682.                          * to have received all response headers.
  1683.                          *
  1684.                          * There are two cases in which we want to suppress
  1685.                          * cacheing of an object:
  1686.                          *
  1687.                          * 1) The HTTP response code is not 200 or 203
  1688.                          * 2) The request URI had a query string and the
  1689.                          *    response headers did not provide an explicit
  1690.                          *    object expiration time.
  1691.                          */
  1692.                         long http_code = fetch_http_code(object->fetch.fetch);
  1693.  
  1694.                         if ((http_code != 200 && http_code != 203) ||
  1695.                                 (object->has_query &&
  1696.                                 (object->cache.max_age == INVALID_AGE &&
  1697.                                         object->cache.expires == 0))) {
  1698.                                 /* Invalidate cache control data */
  1699.                                 llcache_invalidate_cache_control_data(object);
  1700.                         }
  1701.  
  1702.                         /* Release candidate, if any */
  1703.                         if (object->candidate != NULL) {
  1704.                                 object->candidate->candidate_count--;
  1705.                                 object->candidate = NULL;
  1706.                         }
  1707.                 }
  1708.  
  1709.                 object->fetch.state = LLCACHE_FETCH_DATA;
  1710.  
  1711.                 error = llcache_fetch_process_data(object,
  1712.                                 msg->data.header_or_data.buf,
  1713.                                 msg->data.header_or_data.len);
  1714.                 break;
  1715.         case FETCH_FINISHED:
  1716.                 /* Finished fetching */
  1717.         {
  1718.                 uint8_t *temp;
  1719.  
  1720.                 /* DBG("FETCH_FINISHED in llcache\n"); */
  1721.                 object->fetch.state = LLCACHE_FETCH_COMPLETE;
  1722.                 object->fetch.fetch = NULL;
  1723.  
  1724.                 /* Shrink source buffer to required size */
  1725.                 temp = realloc(object->source_data,
  1726.                                 object->source_len);
  1727.                 /* If source_len is 0, then temp may be NULL */
  1728.                 if (temp != NULL || object->source_len == 0) {
  1729.                         object->source_data = temp;
  1730.                         object->source_alloc = object->source_len;
  1731.                 }
  1732.  
  1733.                 llcache_object_cache_update(object);
  1734.         }
  1735.                 break;
  1736.  
  1737.         /* Out-of-band information */
  1738.         case FETCH_ERROR:
  1739.                 /* An error occurred while fetching */
  1740.                 /* The fetch has has already been cleaned up by the fetcher */
  1741.                   /* DBG("FETCH_ERROR in llcache\n"); */
  1742.                 object->fetch.state = LLCACHE_FETCH_COMPLETE;
  1743.                 object->fetch.fetch = NULL;
  1744.  
  1745.                 /* Release candidate, if any */
  1746.                 if (object->candidate != NULL) {
  1747.                         object->candidate->candidate_count--;
  1748.                         object->candidate = NULL;
  1749.                 }
  1750.  
  1751.                 /* Invalidate cache control data */
  1752.                 llcache_invalidate_cache_control_data(object);
  1753.  
  1754.                 /** \todo Consider using errorcode for something */
  1755.  
  1756.                 event.type = LLCACHE_EVENT_ERROR;
  1757.                 event.data.msg = msg->data.error;
  1758.                
  1759.                 error = llcache_send_event_to_users(object, &event);
  1760.                
  1761.                 break;
  1762.         case FETCH_PROGRESS:
  1763.                   /* DBG("FETCH_PROGRESS in llcache\n"); */
  1764.                 /* Progress update */
  1765.                 event.type = LLCACHE_EVENT_PROGRESS;
  1766.                 event.data.msg = msg->data.progress;
  1767.  
  1768.                 error = llcache_send_event_to_users(object, &event);
  1769.                
  1770.                 break;
  1771.  
  1772.         /* Events requiring action */
  1773.         case FETCH_AUTH:
  1774.                   /* DBG("FETCH_AUTH\n"); */
  1775.                 /* Need Authentication */
  1776.  
  1777.                 /* Release candidate, if any */
  1778.                 if (object->candidate != NULL) {
  1779.                         object->candidate->candidate_count--;
  1780.                         object->candidate = NULL;
  1781.                 }
  1782.  
  1783.                 error = llcache_fetch_auth(object, msg->data.auth.realm);
  1784.                 break;
  1785.         case FETCH_CERT_ERR:
  1786.                 /* Something went wrong when validating TLS certificates */
  1787.           /* DBG("FETCH_CERT_ERR\n"); */
  1788.                 /* Release candidate, if any */
  1789.                 if (object->candidate != NULL) {
  1790.                         object->candidate->candidate_count--;
  1791.                         object->candidate = NULL;
  1792.                 }
  1793.  
  1794.                 error = llcache_fetch_cert_error(object,
  1795.                                 msg->data.cert_err.certs,
  1796.                                 msg->data.cert_err.num_certs);
  1797.                 break;
  1798.         case FETCH_SSL_ERR:
  1799.                 /* TLS connection setup failed */
  1800.           /* DBG("FETCH_SSL_ERR\n"); */
  1801.                 /* Release candidate, if any */
  1802.                 if (object->candidate != NULL) {
  1803.                         object->candidate->candidate_count--;
  1804.                         object->candidate = NULL;
  1805.                 }
  1806.  
  1807.                 error = llcache_fetch_ssl_error(object);
  1808.                 break;
  1809.         }
  1810.  
  1811.         /* Deal with any errors reported by event handlers */
  1812.         if (error != NSERROR_OK) {
  1813.           /* DBG("Error is not NSERROR_OK!\n"); */
  1814.                 if (object->fetch.fetch != NULL) {
  1815.                         fetch_abort(object->fetch.fetch);
  1816.                         object->fetch.fetch = NULL;
  1817.  
  1818.                         /* Invalidate cache control data */
  1819.                         llcache_invalidate_cache_control_data(object);
  1820.  
  1821.                         object->fetch.state = LLCACHE_FETCH_COMPLETE;
  1822.                 }
  1823.                 /* DBG("Returning llc_f_cb. (err != NS_OK)\n"); */
  1824.                 return;
  1825.         }
  1826.         /* DBG("Returning from llc_f_cb.(err = NS_OK)\n"); */
  1827. }
  1828.  
  1829. /**
  1830.  * Find a user of a low-level cache object
  1831.  *
  1832.  * \param handle  External cache handle to search for
  1833.  * \return Pointer to corresponding user, or NULL if not found
  1834.  */
  1835. static llcache_object_user *llcache_object_find_user(const llcache_handle *handle)
  1836. {
  1837.         llcache_object_user *user;
  1838.  
  1839.         assert(handle->object != NULL);
  1840.  
  1841.         for (user = handle->object->users; user != NULL; user = user->next) {
  1842.                 if (user->handle == handle)
  1843.                         break;
  1844.         }
  1845.  
  1846.         return user;
  1847. }
  1848.  
  1849. /**
  1850.  * Remove a low-level cache object from a cache list
  1851.  *
  1852.  * \param object  Object to remove
  1853.  * \param list    List to remove from
  1854.  * \return NSERROR_OK
  1855.  */
  1856. static nserror llcache_object_remove_from_list(llcache_object *object,
  1857.                 llcache_object **list)
  1858. {
  1859.         if (object == *list)
  1860.                 *list = object->next;
  1861.         else
  1862.                 object->prev->next = object->next;
  1863.  
  1864.         if (object->next != NULL)
  1865.                 object->next->prev = object->prev;
  1866.  
  1867.         return NSERROR_OK;
  1868. }
  1869.  
  1870. /**
  1871.  * Determine if a low-level cache object resides in a given list
  1872.  *
  1873.  * \param object  Object to search for
  1874.  * \param list    List to search in
  1875.  * \return True if object resides in list, false otherwise
  1876.  */
  1877. static bool llcache_object_in_list(const llcache_object *object,
  1878.                 const llcache_object *list)
  1879. {
  1880.         while (list != NULL) {
  1881.                 if (list == object)
  1882.                         break;
  1883.  
  1884.                 list = list->next;
  1885.         }
  1886.  
  1887.         return list != NULL;
  1888. }
  1889.  
  1890. /**
  1891.  * Notify users of an object's current state
  1892.  *
  1893.  * \param object  Object to notify users about
  1894.  * \return NSERROR_OK on success, appropriate error otherwise
  1895.  */
  1896. static nserror llcache_object_notify_users(llcache_object *object)
  1897. {
  1898.         nserror error;
  1899.         llcache_object_user *user, *next_user;
  1900.         llcache_event event;
  1901.  
  1902. #ifdef LLCACHE_TRACE
  1903.         bool emitted_notify = false;
  1904. #endif
  1905.  
  1906.         /**
  1907.          * State transitions and event emission for users.
  1908.          * Rows: user state. Cols: object state.
  1909.          *
  1910.          * User\Obj     INIT    HEADERS         DATA    COMPLETE
  1911.          * INIT          -         T             T*        T*
  1912.          * HEADERS       -         -             T         T*
  1913.          * DATA          -         -             M         T
  1914.          * COMPLETE      -         -             -         -
  1915.          *
  1916.          * T => transition user to object state
  1917.          * M => no transition required, but may need to emit event
  1918.          *
  1919.          * The transitions marked with an asterisk can be removed by moving
  1920.          * the user context into the subsequent state and then reevaluating.
  1921.          *
  1922.          * Events are issued as follows:
  1923.          *
  1924.          * HAD_HEADERS: on transition from HEADERS -> DATA state
  1925.          * HAD_DATA   : in DATA state, whenever there's new source data
  1926.          * DONE       : on transition from DATA -> COMPLETE state
  1927.          */
  1928.  
  1929.         for (user = object->users; user != NULL; user = next_user) {
  1930.                 /* Emit necessary events to bring the user up-to-date */
  1931.                 llcache_handle *handle = user->handle;
  1932.                 const llcache_fetch_state objstate = object->fetch.state;
  1933.  
  1934.                 /* Flag that this user is the current iteration target
  1935.                  * in case the client attempts to destroy it underneath us */
  1936.                 user->iterator_target = true;
  1937.  
  1938.                 /* A note on the computation of next_user:
  1939.                  *
  1940.                  * Within this loop, we may make a number of calls to
  1941.                  * client code. Our contract with clients is that they
  1942.                  * can do whatever they like from within their callback
  1943.                  * handlers. This is so that we limit the pain of
  1944.                  * reentrancy to this module alone.
  1945.                  *
  1946.                  * One of the things a client can do from within its
  1947.                  * callback handler is to remove users from this object's
  1948.                  * user list. In the common case, the user they attempt
  1949.                  * to remove is the current iteration target, and we
  1950.                  * already protect against that causing problems here.
  1951.                  * However, no such protection exists if the client
  1952.                  * attempts to remove other users from this object's
  1953.                  * user list.
  1954.                  *
  1955.                  * Therefore, we cannot compute next_user up-front
  1956.                  * and expect it to remain valid across calls to
  1957.                  * client code (as the identity of the next user
  1958.                  * in the list may change underneath us). Instead,
  1959.                  * we must compute next_user at the point where we
  1960.                  * are about to cause another iteration of this loop
  1961.                  * (i.e. at the very end, and also at the points where
  1962.                  * continue is used)
  1963.                  */
  1964.  
  1965. #ifdef LLCACHE_TRACE
  1966.                 if (handle->state != objstate) {
  1967.                         if (emitted_notify == false) {
  1968.                                 LOG(("Notifying users of %p", object));
  1969.                                 emitted_notify = true;
  1970.                         }
  1971.  
  1972.                         LOG(("User %p state: %d Object state: %d",
  1973.                                         user, handle->state, objstate));
  1974.                 }
  1975. #endif
  1976.  
  1977.                 /* User: INIT, Obj: HEADERS, DATA, COMPLETE => User->HEADERS */
  1978.                 if (handle->state == LLCACHE_FETCH_INIT &&
  1979.                                 objstate > LLCACHE_FETCH_INIT) {
  1980.                         handle->state = LLCACHE_FETCH_HEADERS;
  1981.                 }
  1982.  
  1983.                 /* User: HEADERS, Obj: DATA, COMPLETE => User->DATA */
  1984.                 if (handle->state == LLCACHE_FETCH_HEADERS &&
  1985.                                 objstate > LLCACHE_FETCH_HEADERS) {
  1986.                         handle->state = LLCACHE_FETCH_DATA;
  1987.  
  1988.                         /* Emit HAD_HEADERS event */
  1989.                         event.type = LLCACHE_EVENT_HAD_HEADERS;
  1990.  
  1991.                         error = handle->cb(handle, &event, handle->pw);
  1992.  
  1993.                         if (user->queued_for_delete) {
  1994.                                 next_user = user->next;
  1995.                                 llcache_object_remove_user(object, user);
  1996.                                 llcache_object_user_destroy(user);
  1997.  
  1998.                                 if (error != NSERROR_OK)
  1999.                                         return error;
  2000.  
  2001.                                 continue;
  2002.                         } else if (error == NSERROR_NEED_DATA) {
  2003.                                 /* User requested replay */
  2004.                                 handle->state = LLCACHE_FETCH_HEADERS;
  2005.  
  2006.                                 /* Continue with the next user -- we'll
  2007.                                  * reemit the event next time round */
  2008.                                 user->iterator_target = false;
  2009.                                 next_user = user->next;
  2010.                                 continue;
  2011.                         } else if (error != NSERROR_OK) {
  2012.                                 user->iterator_target = false;
  2013.                                 return error;
  2014.                         }
  2015.                 }
  2016.  
  2017.                 /* User: DATA, Obj: DATA, COMPLETE, more source available */
  2018.                 if (handle->state == LLCACHE_FETCH_DATA &&
  2019.                                 objstate >= LLCACHE_FETCH_DATA &&
  2020.                                 object->source_len > handle->bytes) {
  2021.                         size_t orig_handle_read;
  2022.  
  2023.                         /* Construct HAD_DATA event */
  2024.                         event.type = LLCACHE_EVENT_HAD_DATA;
  2025.                         event.data.data.buf =
  2026.                                         object->source_data + handle->bytes;
  2027.                         event.data.data.len =
  2028.                                         object->source_len - handle->bytes;
  2029.  
  2030.                         /* Update record of last byte emitted */
  2031.                         if (object->fetch.flags &
  2032.                                         LLCACHE_RETRIEVE_STREAM_DATA) {
  2033.                                 /* Streaming, so reset to zero to
  2034.                                  * minimise amount of cached source data.
  2035.                                  * Additionally, we don't support replay
  2036.                                  * when streaming. */
  2037.                                 orig_handle_read = 0;
  2038.                                 handle->bytes = object->source_len = 0;
  2039.                         } else {
  2040.                                 orig_handle_read = handle->bytes;
  2041.                                 handle->bytes = object->source_len;
  2042.                         }
  2043.  
  2044.                         /* Emit event */
  2045.                         error = handle->cb(handle, &event, handle->pw);
  2046.                         if (user->queued_for_delete) {
  2047.                                 next_user = user->next;
  2048.                                 llcache_object_remove_user(object, user);
  2049.                                 llcache_object_user_destroy(user);
  2050.  
  2051.                                 if (error != NSERROR_OK)
  2052.                                         return error;
  2053.  
  2054.                                 continue;
  2055.                         } else if (error == NSERROR_NEED_DATA) {
  2056.                                 /* User requested replay */
  2057.                                 handle->bytes = orig_handle_read;
  2058.  
  2059.                                 /* Continue with the next user -- we'll
  2060.                                  * reemit the data next time round */
  2061.                                 user->iterator_target = false;
  2062.                                 next_user = user->next;
  2063.                                 continue;
  2064.                         } else if (error != NSERROR_OK) {
  2065.                                 user->iterator_target = false;
  2066.                                 return error;
  2067.                         }
  2068.                 }
  2069.  
  2070.                 /* User: DATA, Obj: COMPLETE => User->COMPLETE */
  2071.                 if (handle->state == LLCACHE_FETCH_DATA &&
  2072.                                 objstate > LLCACHE_FETCH_DATA) {
  2073.                         handle->state = LLCACHE_FETCH_COMPLETE;
  2074.  
  2075.                         /* Emit DONE event */
  2076.                         event.type = LLCACHE_EVENT_DONE;
  2077.  
  2078.                         error = handle->cb(handle, &event, handle->pw);
  2079.                         if (user->queued_for_delete) {
  2080.                                 next_user = user->next;
  2081.                                 llcache_object_remove_user(object, user);
  2082.                                 llcache_object_user_destroy(user);
  2083.  
  2084.                                 if (error != NSERROR_OK)
  2085.                                         return error;
  2086.  
  2087.                                 continue;
  2088.                         } else if (error == NSERROR_NEED_DATA) {
  2089.                                 /* User requested replay */
  2090.                                 handle->state = LLCACHE_FETCH_DATA;
  2091.  
  2092.                                 /* Continue with the next user -- we'll
  2093.                                  * reemit the event next time round */
  2094.                                 user->iterator_target = false;
  2095.                                 next_user = user->next;
  2096.                                 continue;
  2097.                         } else if (error != NSERROR_OK) {
  2098.                                 user->iterator_target = false;
  2099.                                 return error;
  2100.                         }
  2101.                 }
  2102.  
  2103.                 /* No longer the target of an iterator */
  2104.                 user->iterator_target = false;
  2105.  
  2106.                 next_user = user->next;
  2107.         }
  2108.  
  2109.         return NSERROR_OK;
  2110. }
  2111.  
  2112. /**
  2113.  * Make a snapshot of the current state of an llcache_object.
  2114.  *
  2115.  * This has the side-effect of the new object being non-cacheable,
  2116.  * also not-fetching and not a candidate for any other object.
  2117.  *
  2118.  * Also note that this new object has no users and at least one
  2119.  * should be assigned to it before llcache_clean is entered or it
  2120.  * will be immediately cleaned up.
  2121.  *
  2122.  * \param object  The object to take a snapshot of
  2123.  * \param snapshot  Pointer to receive snapshot of \a object
  2124.  * \return NSERROR_OK on success, appropriate error otherwise
  2125.  */
  2126. static nserror llcache_object_snapshot(llcache_object *object,
  2127.                 llcache_object **snapshot)
  2128. {
  2129.         llcache_object *newobj;
  2130.         nserror error;
  2131.        
  2132.         error = llcache_object_new(object->url, &newobj);
  2133.        
  2134.         if (error != NSERROR_OK)
  2135.                 return error;
  2136.        
  2137.         newobj->has_query = object->has_query;
  2138.  
  2139.         newobj->source_alloc = newobj->source_len = object->source_len;
  2140.        
  2141.         if (object->source_len > 0) {
  2142.                 newobj->source_data = malloc(newobj->source_alloc);
  2143.                 if (newobj->source_data == NULL) {
  2144.                         llcache_object_destroy(newobj);
  2145.                         return NSERROR_NOMEM;
  2146.                 }
  2147.                 memcpy(newobj->source_data, object->source_data,
  2148.                                 newobj->source_len);
  2149.         }
  2150.        
  2151.         if (object->num_headers > 0) {
  2152.                 newobj->headers = calloc(sizeof(llcache_header),
  2153.                                 object->num_headers);
  2154.                 if (newobj->headers == NULL) {
  2155.                         llcache_object_destroy(newobj);
  2156.                         return NSERROR_NOMEM;
  2157.                 }
  2158.                 while (newobj->num_headers < object->num_headers) {
  2159.                         llcache_header *nh =
  2160.                                         &(newobj->headers[newobj->num_headers]);
  2161.                         llcache_header *oh =
  2162.                                         &(object->headers[newobj->num_headers]);
  2163.                         newobj->num_headers += 1;
  2164.                         nh->name = strdup(oh->name);
  2165.                         nh->value = strdup(oh->value);
  2166.                         if (nh->name == NULL || nh->value == NULL) {
  2167.                                 llcache_object_destroy(newobj);
  2168.                                 return NSERROR_NOMEM;
  2169.                         }
  2170.                 }
  2171.         }
  2172.        
  2173.         newobj->fetch.state = LLCACHE_FETCH_COMPLETE;
  2174.        
  2175.         *snapshot = newobj;
  2176.        
  2177.         return NSERROR_OK;
  2178. }
  2179.  
  2180.  
  2181. /******************************************************************************
  2182.  * Public API                                                                 *
  2183.  ******************************************************************************/
  2184.  
  2185. /**
  2186.  * Attempt to clean the cache
  2187.  */
  2188. /* Exported interface documented in llcache.h */
  2189. void llcache_clean(void)
  2190. {
  2191.         llcache_object *object, *next;
  2192.         uint32_t llcache_size = 0;
  2193.         int remaining_lifetime;
  2194.  
  2195. #ifdef LLCACHE_TRACE
  2196.         LOG(("Attempting cache clean"));
  2197. #endif
  2198.  
  2199.         /* Candidates for cleaning are (in order of priority):
  2200.          *
  2201.          * 1) Uncacheable objects with no users
  2202.          * 2) Stale cacheable objects with no users or pending fetches
  2203.          * 3) Fresh cacheable objects with no users or pending fetches
  2204.          */
  2205.  
  2206.         /* 1) Uncacheable objects with no users or fetches */
  2207.         for (object = llcache->uncached_objects; object != NULL; object = next) {
  2208.                 next = object->next;
  2209.  
  2210.                 /* The candidate count of uncacheable objects is always 0 */
  2211.                 if ((object->users == NULL) &&
  2212.                     (object->candidate_count == 0) &&
  2213.                     (object->fetch.fetch == NULL) &&
  2214.                     (object->fetch.outstanding_query == false)) {
  2215. #ifdef LLCACHE_TRACE
  2216.                         LOG(("Found victim %p", object));
  2217. #endif
  2218.                         llcache_object_remove_from_list(object,
  2219.                                         &llcache->uncached_objects);
  2220.                         llcache_object_destroy(object);
  2221.                 } else {
  2222.                         llcache_size += object->source_len + sizeof(*object);
  2223.                 }
  2224.         }
  2225.  
  2226.         /* 2) Stale cacheable objects with no users or pending fetches */
  2227.         for (object = llcache->cached_objects; object != NULL; object = next) {
  2228.                 next = object->next;
  2229.  
  2230.                 remaining_lifetime = llcache_object_rfc2616_remaining_lifetime(&object->cache);
  2231.  
  2232.                 if ((object->users == NULL) &&
  2233.                     (object->candidate_count == 0) &&
  2234.                     (object->fetch.fetch == NULL) &&
  2235.                     (object->fetch.outstanding_query == false)) {
  2236.  
  2237.                         if (remaining_lifetime > 0) {
  2238.                                 /* object is fresh */
  2239.                                 llcache_size += object->source_len + sizeof(*object);
  2240.                         } else {
  2241.                                 /* object is not fresh */
  2242. #ifdef LLCACHE_TRACE
  2243.                                 LOG(("Found stale cacheable object (%p) with no users or pending fetches", object));
  2244. #endif
  2245.                                 llcache_object_remove_from_list(object,
  2246.                                                 &llcache->cached_objects);
  2247.                                 llcache_object_destroy(object);
  2248.                         }
  2249.                 } else {
  2250.                         llcache_size += object->source_len + sizeof(*object);
  2251.                 }
  2252.         }
  2253.  
  2254.         /* 3) Fresh cacheable objects with no users or pending
  2255.          * fetches, only if the cache exceeds the configured size.
  2256.          */
  2257.         if (llcache->limit < llcache_size) {
  2258.                 for (object = llcache->cached_objects; object != NULL;
  2259.                                 object = next) {
  2260.                         next = object->next;
  2261.  
  2262.                         if ((object->users == NULL) &&
  2263.                             (object->candidate_count == 0) &&
  2264.                             (object->fetch.fetch == NULL) &&
  2265.                             (object->fetch.outstanding_query == false)) {
  2266. #ifdef LLCACHE_TRACE
  2267.                                 LOG(("Found victim %p", object));
  2268. #endif
  2269.                                 llcache_size -=
  2270.                                         object->source_len + sizeof(*object);
  2271.  
  2272.                                 llcache_object_remove_from_list(object,
  2273.                                                 &llcache->cached_objects);
  2274.                                 llcache_object_destroy(object);
  2275.                         }
  2276.                 }
  2277.         }
  2278.  
  2279. #ifdef LLCACHE_TRACE
  2280.         LOG(("Size: %u", llcache_size));
  2281. #endif
  2282.  
  2283. }
  2284.  
  2285. /* See llcache.h for documentation */
  2286. nserror
  2287. llcache_initialise(llcache_query_callback cb, void *pw, uint32_t llcache_limit)
  2288. {
  2289.         llcache = calloc(1, sizeof(struct llcache_s));
  2290.         if (llcache == NULL) {
  2291.                 return NSERROR_NOMEM;
  2292.         }
  2293.  
  2294.         llcache->query_cb = cb;
  2295.         llcache->query_cb_pw = pw;
  2296.         llcache->limit = llcache_limit;
  2297.  
  2298.         /* Create static scheme strings */
  2299.         if (lwc_intern_string("file", SLEN("file"),
  2300.                         &llcache_file_lwc) != lwc_error_ok)
  2301.                 return NSERROR_NOMEM;
  2302.  
  2303.         if (lwc_intern_string("about", SLEN("about"),
  2304.                         &llcache_about_lwc) != lwc_error_ok)
  2305.                 return NSERROR_NOMEM;
  2306.  
  2307.         if (lwc_intern_string("resource", SLEN("resource"),
  2308.                         &llcache_resource_lwc) != lwc_error_ok)
  2309.                 return NSERROR_NOMEM;
  2310.  
  2311.         LOG(("llcache initialised with a limit of %d bytes", llcache_limit));
  2312.  
  2313.         return NSERROR_OK;
  2314. }
  2315.  
  2316. /* See llcache.h for documentation */
  2317. void llcache_finalise(void)
  2318. {
  2319.         llcache_object *object, *next;
  2320.  
  2321.         /* Clean uncached objects */
  2322.         for (object = llcache->uncached_objects; object != NULL; object = next) {
  2323.                 llcache_object_user *user, *next_user;
  2324.  
  2325.                 next = object->next;
  2326.  
  2327.                 for (user = object->users; user != NULL; user = next_user) {
  2328.                         next_user = user->next;
  2329.  
  2330.                         if (user->handle != NULL)
  2331.                                 free(user->handle);
  2332.  
  2333.                         free(user);
  2334.                 }
  2335.  
  2336.                 /* Fetch system has already been destroyed */
  2337.                 object->fetch.fetch = NULL;
  2338.  
  2339.                 llcache_object_destroy(object);
  2340.         }
  2341.  
  2342.         /* Clean cached objects */
  2343.         for (object = llcache->cached_objects; object != NULL; object = next) {
  2344.                 llcache_object_user *user, *next_user;
  2345.  
  2346.                 next = object->next;
  2347.  
  2348.                 for (user = object->users; user != NULL; user = next_user) {
  2349.                         next_user = user->next;
  2350.  
  2351.                         if (user->handle != NULL)
  2352.                                free(user->handle);
  2353.  
  2354.                         free(user);
  2355.                 }
  2356.  
  2357.                 /* Fetch system has already been destroyed */
  2358.                 object->fetch.fetch = NULL;            
  2359.  
  2360.                 llcache_object_destroy(object);
  2361.         }
  2362.  
  2363.         /* Unref static scheme lwc strings */
  2364.         lwc_string_unref(llcache_file_lwc);
  2365.         lwc_string_unref(llcache_about_lwc);
  2366.         lwc_string_unref(llcache_resource_lwc);
  2367.  
  2368.         free(llcache);
  2369.         llcache = NULL;
  2370. }
  2371.  
  2372. /* See llcache.h for documentation */
  2373. nserror llcache_poll(void)
  2374. {
  2375.         llcache_object *object;
  2376.         fetch_poll();
  2377.        
  2378.         /* Catch new users up with state of objects */
  2379.         for (object = llcache->cached_objects; object != NULL;
  2380.                         object = object->next) {
  2381.                 llcache_object_notify_users(object);
  2382.         }
  2383.  
  2384.         for (object = llcache->uncached_objects; object != NULL;
  2385.                         object = object->next) {
  2386.                 llcache_object_notify_users(object);
  2387.         }
  2388.  
  2389.         return NSERROR_OK;
  2390. }
  2391.  
  2392. /* See llcache.h for documentation */
  2393. nserror llcache_handle_retrieve(nsurl *url, uint32_t flags,
  2394.                 nsurl *referer, const llcache_post_data *post,
  2395.                 llcache_handle_callback cb, void *pw,
  2396.                 llcache_handle **result)
  2397. {
  2398.         nserror error;
  2399.         llcache_object_user *user;
  2400.         llcache_object *object;
  2401.  
  2402.         /* Can we fetch this URL at all? */
  2403.         if (fetch_can_fetch(url) == false)
  2404.                 return NSERROR_NO_FETCH_HANDLER;
  2405.  
  2406.         /* Create a new object user */
  2407.         error = llcache_object_user_new(cb, pw, &user);
  2408.         if (error != NSERROR_OK)
  2409.                 return error;
  2410.  
  2411.         /* Retrieve a suitable object from the cache,
  2412.          * creating a new one if needed. */
  2413.         error = llcache_object_retrieve(url, flags, referer, post, 0, &object);
  2414.         if (error != NSERROR_OK) {
  2415.                 llcache_object_user_destroy(user);
  2416.                 return error;
  2417.         }
  2418.  
  2419.         /* Add user to object */
  2420.         llcache_object_add_user(object, user);
  2421.  
  2422.         *result = user->handle;
  2423.  
  2424.         return NSERROR_OK;
  2425. }
  2426.  
  2427. /* See llcache.h for documentation */
  2428. nserror llcache_handle_change_callback(llcache_handle *handle,
  2429.                 llcache_handle_callback cb, void *pw)
  2430. {
  2431.         handle->cb = cb;
  2432.         handle->pw = pw;
  2433.  
  2434.         return NSERROR_OK;
  2435. }
  2436.  
  2437. /* See llcache.h for documentation */
  2438. nserror llcache_handle_release(llcache_handle *handle)
  2439. {
  2440.         nserror error = NSERROR_OK;
  2441.         llcache_object *object = handle->object;
  2442.         llcache_object_user *user = llcache_object_find_user(handle);
  2443.  
  2444.         assert(user != NULL);
  2445.  
  2446.         if (user->iterator_target) {
  2447.                 /* Can't remove / delete user object if it's
  2448.                  * the target of an iterator */
  2449.                 user->queued_for_delete = true;
  2450.         } else {
  2451.                 /* Remove the user from the object and destroy it */
  2452.                 error = llcache_object_remove_user(object, user);
  2453.                 if (error == NSERROR_OK) {
  2454.                         error = llcache_object_user_destroy(user);
  2455.                 }
  2456.         }
  2457.        
  2458.         return error;
  2459. }
  2460.  
  2461. /* See llcache.h for documentation */
  2462. nserror llcache_handle_clone(llcache_handle *handle, llcache_handle **result)
  2463. {
  2464.         nserror error;
  2465.         llcache_object_user *newuser;
  2466.                
  2467.         error = llcache_object_user_new(handle->cb, handle->pw, &newuser);
  2468.         if (error == NSERROR_OK) {
  2469.                 llcache_object_add_user(handle->object, newuser);
  2470.                 newuser->handle->state = handle->state;
  2471.                 *result = newuser->handle;
  2472.         }
  2473.        
  2474.         return error;
  2475. }
  2476.  
  2477. /* See llcache.h for documentation */
  2478. nserror llcache_handle_abort(llcache_handle *handle)
  2479. {
  2480.         llcache_object_user *user = llcache_object_find_user(handle);
  2481.         llcache_object *object = handle->object, *newobject;
  2482.         nserror error = NSERROR_OK;
  2483.         bool all_alone = true;
  2484.        
  2485.         /* Determine if we are the only user */
  2486.         if (user->prev != NULL)
  2487.                 all_alone = false;
  2488.         if (user->next != NULL)
  2489.                 all_alone = false;
  2490.        
  2491.         if (all_alone == false) {
  2492.                 /* We must snapshot this object */
  2493.                 error = llcache_object_snapshot(object, &newobject);
  2494.                 if (error != NSERROR_OK)
  2495.                         return error;
  2496.  
  2497.                 /* Move across to the new object */
  2498.                 if (user->iterator_target) {
  2499.                         /* User is current iterator target, clone it */
  2500.                         llcache_object_user *newuser =
  2501.                                         calloc(1, sizeof(llcache_object_user));
  2502.                         if (newuser == NULL) {
  2503.                                 llcache_object_destroy(newobject);
  2504.                                 return NSERROR_NOMEM;
  2505.                         }
  2506.  
  2507.                         /* Move handle across to clone */
  2508.                         newuser->handle = user->handle;
  2509.                         user->handle = NULL;
  2510.  
  2511.                         /* Mark user as needing deletion */
  2512.                         user->queued_for_delete = true;
  2513.  
  2514.                         llcache_object_add_user(newobject, newuser);
  2515.                 } else {
  2516.                         llcache_object_remove_user(object, user);
  2517.                         llcache_object_add_user(newobject, user);
  2518.                 }
  2519.                
  2520.                 /* Add new object to uncached list */
  2521.                 llcache_object_add_to_list(newobject,
  2522.                                 &llcache->uncached_objects);
  2523.         } else {
  2524.                 /* We're the only user, so abort any fetch in progress */
  2525.                 if (object->fetch.fetch != NULL) {
  2526.                         fetch_abort(object->fetch.fetch);
  2527.                         object->fetch.fetch = NULL;
  2528.                 }
  2529.                
  2530.                 object->fetch.state = LLCACHE_FETCH_COMPLETE;
  2531.                
  2532.                 /* Invalidate cache control data */
  2533.                 llcache_invalidate_cache_control_data(object);
  2534.         }
  2535.        
  2536.         return error;
  2537. }
  2538.  
  2539. /* See llcache.h for documentation */
  2540. nserror llcache_handle_force_stream(llcache_handle *handle)
  2541. {
  2542.         llcache_object_user *user = llcache_object_find_user(handle);
  2543.         llcache_object *object = handle->object;
  2544.  
  2545.         /* Cannot stream if there are multiple users */
  2546.         if (user->prev != NULL || user->next != NULL)
  2547.                 return NSERROR_OK;
  2548.  
  2549.         /* Forcibly uncache this object */
  2550.         if (llcache_object_in_list(object, llcache->cached_objects)) {
  2551.                 llcache_object_remove_from_list(object,
  2552.                                 &llcache->cached_objects);
  2553.                 llcache_object_add_to_list(object, &llcache->uncached_objects);
  2554.         }
  2555.  
  2556.         object->fetch.flags |= LLCACHE_RETRIEVE_STREAM_DATA;
  2557.  
  2558.         return NSERROR_OK;
  2559. }
  2560.  
  2561. /* See llcache.h for documentation */
  2562. nserror llcache_handle_invalidate_cache_data(llcache_handle *handle)
  2563. {
  2564.         if (handle->object != NULL && handle->object->fetch.fetch == NULL &&
  2565.                         handle->object->cache.no_cache ==
  2566.                                 LLCACHE_VALIDATE_FRESH) {
  2567.                 handle->object->cache.no_cache = LLCACHE_VALIDATE_ONCE;
  2568.         }
  2569.  
  2570.         return NSERROR_OK;
  2571. }
  2572.  
  2573. /* See llcache.h for documentation */
  2574. nsurl *llcache_handle_get_url(const llcache_handle *handle)
  2575. {
  2576.         return handle->object != NULL ? handle->object->url : NULL;
  2577. }
  2578.  
  2579. /* See llcache.h for documentation */
  2580. const uint8_t *llcache_handle_get_source_data(const llcache_handle *handle,
  2581.                 size_t *size)
  2582. {
  2583.         *size = handle->object != NULL ? handle->object->source_len : 0;
  2584.  
  2585.         return handle->object != NULL ? handle->object->source_data : NULL;
  2586. }
  2587.  
  2588. /* See llcache.h for documentation */
  2589. const char *llcache_handle_get_header(const llcache_handle *handle,
  2590.                 const char *key)
  2591. {
  2592.         const llcache_object *object = handle->object;
  2593.         size_t i;
  2594.  
  2595.         if (object == NULL)
  2596.                 return NULL;
  2597.  
  2598.         /* About as trivial as possible */
  2599.         for (i = 0; i < object->num_headers; i++) {
  2600.                 if (strcasecmp(key, object->headers[i].name) == 0)
  2601.                         return object->headers[i].value;
  2602.         }
  2603.  
  2604.         return NULL;
  2605. }
  2606.  
  2607. /* See llcache.h for documentation */
  2608. bool llcache_handle_references_same_object(const llcache_handle *a,
  2609.                 const llcache_handle *b)
  2610. {
  2611.         return a->object == b->object;
  2612. }
  2613.  
  2614.