NetSurf
hlcache.c
Go to the documentation of this file.
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/**
20 * \file
21 * High-level resource cache implementation.
22 */
23
24#include <assert.h>
25#include <stdlib.h>
26#include <string.h>
27
28#include "utils/http.h"
29#include "utils/log.h"
30#include "utils/messages.h"
31#include "utils/ring.h"
32#include "utils/utils.h"
33#include "netsurf/inttypes.h"
34#include "netsurf/misc.h"
35#include "netsurf/content.h"
37
38#include "content/mimesniff.h"
39#include "content/hlcache.h"
40// Note, this is *ONLY* so that we can abort cleanly during shutdown of the cache
43
46
47/** High-level cache retrieval context */
49 struct hlcache_retrieval_ctx *r_prev; /**< Previous retrieval context in the ring */
50 struct hlcache_retrieval_ctx *r_next; /**< Next retrieval context in the ring */
51
52 llcache_handle *llcache; /**< Low-level cache handle */
53
54 hlcache_handle *handle; /**< High-level handle for object */
55
56 uint32_t flags; /**< Retrieval flags */
57
58 content_type accepted_types; /**< Accepted types */
59
60 hlcache_child_context child; /**< Child context */
61
62 bool migrate_target; /**< Whether this context is the migration target */
63};
64
65/** High-level cache handle */
67 hlcache_entry *entry; /**< Pointer to cache entry */
68
69 hlcache_handle_callback cb; /**< Client callback */
70 void *pw; /**< Client data */
71};
72
73/** Entry in high-level cache */
75 struct content *content; /**< Pointer to associated content */
76
77 hlcache_entry *next; /**< Next sibling */
78 hlcache_entry *prev; /**< Previous sibling */
79};
80
81/** Current state of the cache.
82 *
83 * Global state of the cache.
84 */
85struct hlcache_s {
87
88 /** List of cached content objects */
90
91 /** Ring of retrieval contexts */
93
94 /* statistics */
95 unsigned int hit_count;
96 unsigned int miss_count;
97};
98
99/** high level cache state */
100static struct hlcache_s *hlcache = NULL;
101
102
103/******************************************************************************
104 * High-level cache internals *
105 ******************************************************************************/
106
107
108/**
109 * Attempt to clean the cache
110 */
111static void hlcache_clean(void *force_clean_flag)
112{
113 hlcache_entry *entry, *next;
114 bool force_clean = (force_clean_flag != NULL);
115
116 for (entry = hlcache->content_list; entry != NULL; entry = next) {
117 next = entry->next;
118
119 if (entry->content == NULL)
120 continue;
121
122 if (content_count_users(entry->content) != 0)
123 continue;
124
126 if (force_clean == false)
127 continue;
128 NSLOG(netsurf, DEBUG, "Forcing content cleanup during shutdown");
129 content_abort(entry->content);
131 }
132
133 /** \todo This is over-zealous: all unused contents
134 * will be immediately destroyed. Ideally, we want to
135 * purge all unused contents that are using stale
136 * source data, and enough fresh contents such that
137 * the cache fits in the configured cache size limit.
138 */
139
140 /* Remove entry from cache */
141 if (entry->prev == NULL)
142 hlcache->content_list = entry->next;
143 else
144 entry->prev->next = entry->next;
145
146 if (entry->next != NULL)
147 entry->next->prev = entry->prev;
148
149 /* Destroy content */
150 content_destroy(entry->content);
151
152 /* Destroy entry */
153 free(entry);
154 }
155
156 /* Attempt to clean the llcache */
157 llcache_clean(false);
158
159 /* Re-schedule ourselves */
161}
162
163/**
164 * Determine if the specified MIME type is acceptable
165 *
166 * \param mime_type MIME type to consider
167 * \param accepted_types Array of acceptable types, or NULL for any
168 * \param computed_type Pointer to location to receive computed type of object
169 * \return True if the type is acceptable, false otherwise
170 */
171static bool hlcache_type_is_acceptable(lwc_string *mime_type,
172 content_type accepted_types, content_type *computed_type)
173{
175
177
178 *computed_type = type;
179
180 return ((accepted_types & type) != 0);
181}
182
183/**
184 * Veneer between content callback API and hlcache callback API
185 *
186 * \param c Content to emit message for
187 * \param msg Message to emit
188 * \param data Data for message
189 * \param pw Pointer to private data (hlcache_handle)
190 */
192 const union content_msg_data *data, void *pw)
193{
194 hlcache_handle *handle = pw;
195 nserror error = NSERROR_OK;
196 hlcache_event event = {
197 .type = msg,
198 };
199
200 if (data != NULL) {
201 event.data = *data;
202 }
203
204 if (handle->cb != NULL)
205 error = handle->cb(handle, &event, handle->pw);
206
207 if (error != NSERROR_OK)
208 NSLOG(netsurf, INFO, "Error in callback: %d", error);
209}
210
211/**
212 * Find a content for the high-level cache handle
213 *
214 * \param ctx High-level cache retrieval context
215 * \param effective_type Effective MIME type of content
216 * \return NSERROR_OK on success,
217 * NSERROR_NEED_DATA on success where data is needed,
218 * appropriate error otherwise
219 *
220 * \pre handle::state == HLCACHE_HANDLE_NEW
221 * \pre Headers must have been received for associated low-level handle
222 * \post Low-level handle is either released, or associated with new content
223 * \post High-level handle is registered with content
224 */
226 lwc_string *effective_type)
227{
228 hlcache_entry *entry;
229 hlcache_event event;
230 nserror error = NSERROR_OK;
231
232 /* Search list of cached contents for a suitable one */
233 for (entry = hlcache->content_list; entry != NULL; entry = entry->next) {
234 hlcache_handle entry_handle = { entry, NULL, NULL };
235 const llcache_handle *entry_llcache;
236
237 if (entry->content == NULL)
238 continue;
239
240 /* Ignore contents in the error state */
241 if (content_get_status(&entry_handle) == CONTENT_STATUS_ERROR)
242 continue;
243
244 /* Ensure that content is shareable */
245 if (content_is_shareable(entry->content) == false)
246 continue;
247
248 /* Ensure that quirks mode is acceptable */
250 ctx->child.quirks) == false)
251 continue;
252
253 /* Ensure that content uses same low-level object as
254 * low-level handle */
255 entry_llcache = content_get_llcache_handle(entry->content);
256
258 ctx->llcache))
259 break;
260 }
261
262 if (entry == NULL) {
263 /* No existing entry, so need to create one */
264 entry = malloc(sizeof(hlcache_entry));
265 if (entry == NULL)
266 return NSERROR_NOMEM;
267
268 /* Create content using llhandle */
270 ctx->child.charset, ctx->child.quirks,
271 effective_type);
272 if (entry->content == NULL) {
273 free(entry);
274 return NSERROR_NOMEM;
275 }
276
277 /* Insert into cache */
278 entry->prev = NULL;
279 entry->next = hlcache->content_list;
280 if (hlcache->content_list != NULL)
281 hlcache->content_list->prev = entry;
282 hlcache->content_list = entry;
283
284 /* Signal to caller that we created a content */
285 error = NSERROR_NEED_DATA;
286
288 } else {
289 /* Found a suitable content: no longer need low-level handle */
292 }
293
294 /* Associate handle with content */
295 if (content_add_user(entry->content,
296 hlcache_content_callback, ctx->handle) == false)
297 return NSERROR_NOMEM;
298
299 /* Associate cache entry with handle */
300 ctx->handle->entry = entry;
301
302 /* Catch handle up with state of content */
303 if (ctx->handle->cb != NULL) {
305
306 if (status == CONTENT_STATUS_LOADING) {
307 event.type = CONTENT_MSG_LOADING;
308 ctx->handle->cb(ctx->handle, &event, ctx->handle->pw);
309 } else if (status == CONTENT_STATUS_READY) {
310 event.type = CONTENT_MSG_LOADING;
311 ctx->handle->cb(ctx->handle, &event, ctx->handle->pw);
312
313 if (ctx->handle->cb != NULL) {
314 event.type = CONTENT_MSG_READY;
315 ctx->handle->cb(ctx->handle, &event,
316 ctx->handle->pw);
317 }
318 } else if (status == CONTENT_STATUS_DONE) {
319 event.type = CONTENT_MSG_LOADING;
320 ctx->handle->cb(ctx->handle, &event, ctx->handle->pw);
321
322 if (ctx->handle->cb != NULL) {
323 event.type = CONTENT_MSG_READY;
324 ctx->handle->cb(ctx->handle, &event,
325 ctx->handle->pw);
326 }
327
328 if (ctx->handle->cb != NULL) {
329 event.type = CONTENT_MSG_DONE;
330 ctx->handle->cb(ctx->handle, &event,
331 ctx->handle->pw);
332 }
333 }
334 }
335
336 return error;
337}
338
339/**
340 * Migrate a retrieval context into its final destination content
341 *
342 * \param ctx Context to migrate
343 * \param effective_type The effective MIME type of the content, or NULL
344 * \return NSERROR_OK on success,
345 * NSERROR_NEED_DATA on success where data is needed,
346 * appropriate error otherwise
347 */
349 lwc_string *effective_type)
350{
352 nserror error = NSERROR_OK;
353
354 ctx->migrate_target = true;
355
356 if ((effective_type != NULL) &&
357 hlcache_type_is_acceptable(effective_type,
358 ctx->accepted_types,
359 &type)) {
360 error = hlcache_find_content(ctx, effective_type);
361 if (error != NSERROR_OK && error != NSERROR_NEED_DATA) {
362 if (ctx->handle->cb != NULL) {
363 hlcache_event hlevent;
364
365 hlevent.type = CONTENT_MSG_ERROR;
367 hlevent.data.errordata.errormsg = messages_get("MiscError");
368
369 ctx->handle->cb(ctx->handle, &hlevent,
370 ctx->handle->pw);
371 }
372
375 }
376 } else if (type == CONTENT_NONE &&
378 /* Unknown type, and we can download, so convert */
380
381 if (ctx->handle->cb != NULL) {
382 hlcache_event hlevent;
383
384 hlevent.type = CONTENT_MSG_DOWNLOAD;
385 hlevent.data.download = ctx->llcache;
386
387 ctx->handle->cb(ctx->handle, &hlevent,
388 ctx->handle->pw);
389 }
390
391 /* Ensure caller knows we need data */
392 error = NSERROR_NEED_DATA;
393 } else {
394 /* Unacceptable type: report error */
395 if (ctx->handle->cb != NULL) {
396 hlcache_event hlevent;
397
398 hlevent.type = CONTENT_MSG_ERROR;
400 hlevent.data.errordata.errormsg = messages_get("UnacceptableType");
401
402 ctx->handle->cb(ctx->handle, &hlevent,
403 ctx->handle->pw);
404 }
405
408 }
409
410 ctx->migrate_target = false;
411
412 /* No longer require retrieval context */
414 free((char *) ctx->child.charset);
415 free(ctx);
416
417 return error;
418}
419
420/**
421 * Handler for low-level cache events
422 *
423 * \param handle Handle for which event is issued
424 * \param event Event data
425 * \param pw Pointer to client-specific data
426 * \return NSERROR_OK on success, appropriate error otherwise
427 */
428static nserror
430 const llcache_event *event,
431 void *pw)
432{
433 hlcache_retrieval_ctx *ctx = pw;
434 lwc_string *effective_type = NULL;
435 nserror error;
436
437 assert(ctx->llcache == handle);
438
439 switch (event->type) {
441 /* Pass them on upward */
442 if (ctx->handle->cb != NULL) {
443 hlcache_event hlevent;
444
445 hlevent.type = CONTENT_MSG_SSL_CERTS;
446 hlevent.data.chain = event->data.chain;
447
448 ctx->handle->cb(ctx->handle, &hlevent, ctx->handle->pw);
449 }
450 break;
452 error = mimesniff_compute_effective_type(llcache_handle_get_header(handle, "Content-Type"), NULL, 0,
455 &effective_type);
456 if (error == NSERROR_OK || error == NSERROR_NOT_FOUND) {
457 /* If the sniffer was successful or failed to find
458 * a Content-Type header when sniffing was
459 * prohibited, we must migrate the retrieval context. */
460 error = hlcache_migrate_ctx(ctx, effective_type);
461
462 lwc_string_unref(effective_type);
463 }
464
465 /* No need to report that we need data:
466 * we'll get some anyway if there is any */
467 if (error == NSERROR_NEED_DATA)
468 error = NSERROR_OK;
469
470 return error;
471
472 break;
474 error = mimesniff_compute_effective_type(llcache_handle_get_header(handle, "Content-Type"),
475 event->data.data.buf, event->data.data.len,
478 &effective_type);
479 if (error != NSERROR_OK) {
480 assert(0 && "MIME sniff failed with data");
481 }
482
483 error = hlcache_migrate_ctx(ctx, effective_type);
484
485 lwc_string_unref(effective_type);
486
487 return error;
488
489 break;
491 /* DONE event before we could determine the effective MIME type.
492 */
493 error = mimesniff_compute_effective_type(llcache_handle_get_header(handle, "Content-Type"),
494 NULL, 0, false, false, &effective_type);
495 if (error == NSERROR_OK || error == NSERROR_NOT_FOUND) {
496 error = hlcache_migrate_ctx(ctx, effective_type);
497
498 lwc_string_unref(effective_type);
499 return error;
500 }
501
502 if (ctx->handle->cb != NULL) {
503 hlcache_event hlevent;
504
505 hlevent.type = CONTENT_MSG_ERROR;
506 hlevent.data.errordata.errorcode = error;
507 hlevent.data.errordata.errormsg = NULL;
508
509 ctx->handle->cb(ctx->handle, &hlevent, ctx->handle->pw);
510 }
511 break;
513 if (ctx->handle->cb != NULL) {
514 hlcache_event hlevent;
515
516 hlevent.type = CONTENT_MSG_ERROR;
517 hlevent.data.errordata.errorcode = event->data.error.code;
518 hlevent.data.errordata.errormsg = event->data.error.msg;
519
520 ctx->handle->cb(ctx->handle, &hlevent, ctx->handle->pw);
521 }
522 break;
524 break;
526 if (ctx->handle->cb != NULL) {
527 hlcache_event hlevent;
528
529 hlevent.type = CONTENT_MSG_REDIRECT;
530 hlevent.data.redirect.from = event->data.redirect.from;
531 hlevent.data.redirect.to = event->data.redirect.to;
532
533 ctx->handle->cb(ctx->handle, &hlevent, ctx->handle->pw);
534 }
535 break;
536 }
537
538 return NSERROR_OK;
539}
540
541
542/******************************************************************************
543 * Public API *
544 ******************************************************************************/
545
546
549{
550 nserror ret;
551
552 hlcache = calloc(1, sizeof(struct hlcache_s));
553 if (hlcache == NULL) {
554 return NSERROR_NOMEM;
555 }
556
558 if (ret != NSERROR_OK) {
559 free(hlcache);
560 hlcache = NULL;
561 return ret;
562 }
563
565
566 /* Schedule the cache cleanup */
568
569 return NSERROR_OK;
570}
571
572/* See hlcache.h for documentation */
573void hlcache_stop(void)
574{
575 /* Remove the hlcache_clean schedule */
576 guit->misc->schedule(-1, hlcache_clean, NULL);
577}
578
579/* See hlcache.h for documentation */
581{
582 uint32_t num_contents, prev_contents;
583 hlcache_entry *entry;
584 hlcache_retrieval_ctx *ctx, *next;
585
586 /* Obtain initial count of contents remaining */
587 for (num_contents = 0, entry = hlcache->content_list;
588 entry != NULL; entry = entry->next) {
589 num_contents++;
590 }
591
592 NSLOG(netsurf, INFO, "%"PRIu32" contents remain before cache drain",
593 num_contents);
594
595 /* Drain cache */
596 do {
597 prev_contents = num_contents;
598
599 hlcache_clean(NULL);
600
601 for (num_contents = 0, entry = hlcache->content_list;
602 entry != NULL; entry = entry->next) {
603 num_contents++;
604 }
605 } while (num_contents > 0 && num_contents != prev_contents);
606
607 NSLOG(netsurf, INFO, "%"PRIu32" contents remaining after being polite",
608 num_contents);
609
610 /* Drain cache again, forcing the matter */
611 do {
612 prev_contents = num_contents;
613
614 hlcache_clean(&entry); // Any non-NULL pointer will do
615
616 for (num_contents = 0, entry = hlcache->content_list;
617 entry != NULL; entry = entry->next) {
618 num_contents++;
619 }
620 } while (num_contents > 0 && num_contents != prev_contents);
621
622 NSLOG(netsurf, INFO, "%"PRIu32" contents remaining:", num_contents);
623 for (entry = hlcache->content_list; entry != NULL; entry = entry->next) {
624 hlcache_handle entry_handle = { entry, NULL, NULL };
625
626 if (entry->content != NULL) {
627 NSLOG(netsurf, INFO, " %p : %s (%"PRIu32" users)",
628 entry,
629 nsurl_access(hlcache_handle_get_url(&entry_handle)),
631 } else {
632 NSLOG(netsurf, INFO, " %p", entry);
633 }
634 }
635
636 /* Clean up retrieval contexts */
637 if (hlcache->retrieval_ctx_ring != NULL) {
639
640 do {
641 next = ctx->r_next;
642
643 if (ctx->llcache != NULL)
645
646 if (ctx->handle != NULL)
647 free(ctx->handle);
648
649 if (ctx->child.charset != NULL)
650 free((char *) ctx->child.charset);
651
652 free(ctx);
653
654 ctx = next;
655 } while (ctx != hlcache->retrieval_ctx_ring);
656
658 }
659
660 NSLOG(netsurf, INFO, "hit/miss %d/%d", hlcache->hit_count,
662
663 /* De-schedule ourselves */
664 guit->misc->schedule(-1, hlcache_clean, NULL);
665
666 free(hlcache);
667 hlcache = NULL;
668
669 NSLOG(netsurf, INFO, "Finalising low-level cache");
671}
672
673/* See hlcache.h for documentation */
676 uint32_t flags,
677 nsurl *referer,
678 llcache_post_data *post,
679 hlcache_handle_callback cb, void *pw,
681 content_type accepted_types,
683{
685 nserror error;
686
687 assert(cb != NULL);
688
689 ctx = calloc(1, sizeof(hlcache_retrieval_ctx));
690 if (ctx == NULL) {
691 return NSERROR_NOMEM;
692 }
693
694 ctx->handle = calloc(1, sizeof(hlcache_handle));
695 if (ctx->handle == NULL) {
696 free(ctx);
697 return NSERROR_NOMEM;
698 }
699
700 if (child != NULL) {
701 if (child->charset != NULL) {
702 ctx->child.charset = strdup(child->charset);
703 if (ctx->child.charset == NULL) {
704 free(ctx->handle);
705 free(ctx);
706 return NSERROR_NOMEM;
707 }
708 }
709 ctx->child.quirks = child->quirks;
710 }
711
712 ctx->flags = flags;
713 ctx->accepted_types = accepted_types;
714
715 ctx->handle->cb = cb;
716 ctx->handle->pw = pw;
717
718 error = llcache_handle_retrieve(url, flags, referer, post,
720 &ctx->llcache);
721 if (error != NSERROR_OK) {
722 /* error retrieving handle so free context and return error */
723 free((char *) ctx->child.charset);
724 free(ctx->handle);
725 free(ctx);
726 } else {
727 /* successfully started fetch so add new context to list */
729
730 *result = ctx->handle;
731 }
732 return error;
733}
734
735/* See hlcache.h for documentation */
737{
738 if (handle->entry != NULL) {
741 } else {
744 ictx) {
745 if (ictx->handle == handle &&
746 ictx->migrate_target == false) {
747 /* This is the nascent context for us,
748 * so abort the fetch */
749 llcache_handle_abort(ictx->llcache);
750 llcache_handle_release(ictx->llcache);
751 /* Remove us from the ring */
753 /* Throw us away */
754 free((char *) ictx->child.charset);
755 free(ictx);
756 /* And stop */
758 ictx);
759 }
761 }
762
763 handle->cb = NULL;
764 handle->pw = NULL;
765
766 free(handle);
767
768 return NSERROR_OK;
769}
770
771/* See hlcache.h for documentation */
773{
774 if ((handle != NULL) && (handle->entry != NULL)) {
775 return handle->entry->content;
776 }
777
778 return NULL;
779}
780
781/* See hlcache.h for documentation */
783{
784 struct hlcache_entry *entry = handle->entry;
785 struct content *c;
786
787 if (entry == NULL) {
788 /* This handle is not yet associated with a cache entry.
789 * The implication is that the fetch for the handle has
790 * not progressed to the point where the entry can be
791 * created. */
792
795 ictx) {
796 if (ictx->handle == handle &&
797 ictx->migrate_target == false) {
798 /* This is the nascent context for us,
799 * so abort the fetch */
800 llcache_handle_abort(ictx->llcache);
801 llcache_handle_release(ictx->llcache);
802 /* Remove us from the ring */
804 /* Throw us away */
805 free((char *) ictx->child.charset);
806 free(ictx);
807 /* And stop */
809 ictx);
810 }
812
813 return NSERROR_OK;
814 }
815
816 c = entry->content;
817
818 if (content_count_users(c) > 1) {
819 /* We are not the only user of 'c' so clone it. */
820 struct content *clone = content_clone(c);
821
822 if (clone == NULL)
823 return NSERROR_NOMEM;
824
825 entry = calloc(1, sizeof(struct hlcache_entry));
826
827 if (entry == NULL) {
828 content_destroy(clone);
829 return NSERROR_NOMEM;
830 }
831
832 if (content_add_user(clone,
833 hlcache_content_callback, handle) == false) {
834 content_destroy(clone);
835 free(entry);
836 return NSERROR_NOMEM;
837 }
838
840
841 entry->content = clone;
842 handle->entry = entry;
843 entry->prev = NULL;
844 entry->next = hlcache->content_list;
845 if (hlcache->content_list != NULL)
846 hlcache->content_list->prev = entry;
847 hlcache->content_list = entry;
848
849 c = clone;
850 }
851
852 return content_abort(c);
853}
854
855/* See hlcache.h for documentation */
857 hlcache_handle_callback cb, void *pw)
858{
859 handle->cb = cb;
860 handle->pw = pw;
861
862 return NSERROR_OK;
863}
864
866{
867 *result = NULL;
869}
870
871/* See hlcache.h for documentation */
873{
874 nsurl *result = NULL;
875
876 assert(handle != NULL);
877
878 if (handle->entry != NULL) {
880 } else {
883 ictx) {
884 if (ictx->handle == handle) {
885 /* This is the nascent context for us */
886 result = llcache_handle_get_url(ictx->llcache);
887
888 /* And stop */
890 ictx);
891 }
893 }
894
895 return result;
896}
STATIC char result[100]
Definition: arexx.c:77
void content_destroy(struct content *c)
Destroy and free a content.
Definition: content.c:354
void content_remove_user(struct content *c, void(*callback)(struct content *c, content_msg msg, const union content_msg_data *data, void *pw), void *pw)
Remove a callback user.
Definition: content.c:684
uint32_t content_count_users(struct content *c)
Count users for the content.
Definition: content.c:718
bool content_is_shareable(struct content *c)
Determine if a content is shareable.
Definition: content.c:745
void content_set_error(struct content *c)
Put a content in status CONTENT_STATUS_ERROR and unlock the content.
Definition: content.c:313
content_status content__get_status(struct content *c)
Retrieve status of content.
Definition: content.c:1123
nsurl * content_get_url(struct content *c)
Retrieve URL associated with content.
Definition: content.c:1043
bool content_add_user(struct content *c, void(*callback)(struct content *c, content_msg msg, const union content_msg_data *data, void *pw), void *pw)
Register a user for callbacks.
Definition: content.c:654
struct content * content_clone(struct content *c)
Clone a content object in its current state.
Definition: content.c:1360
bool content_matches_quirks(struct content *c, bool quirks)
Determine if quirks mode matches.
Definition: content.c:735
nserror content_abort(struct content *c)
Abort a content object.
Definition: content.c:1440
const llcache_handle * content_get_llcache_handle(struct content *c)
Retrieve the low-level cache handle for a content.
Definition: content.c:1350
content_status content_get_status(hlcache_handle *h)
Retrieve status of content.
Definition: content.c:1116
content_type content_factory_type_from_mime_type(lwc_string *mime_type)
Compute the generic content type for a MIME type.
struct content * content_factory_create_content(llcache_handle *llcache, const char *fallback_charset, bool quirks, lwc_string *effective_type)
Create a content object.
Protected interface to Content handling.
content_status
Status of a content.
Definition: content_type.h:87
@ CONTENT_STATUS_READY
Some parts of content still being loaded, but can be displayed.
Definition: content_type.h:92
@ CONTENT_STATUS_DONE
Content has completed all processing.
Definition: content_type.h:95
@ CONTENT_STATUS_ERROR
Error occurred, content will be destroyed imminently.
Definition: content_type.h:98
@ CONTENT_STATUS_LOADING
Content is being fetched or converted and is not safe to display.
Definition: content_type.h:89
content_type
The type of a content.
Definition: content_type.h:53
@ CONTENT_IMAGE
All images.
Definition: content_type.h:67
@ CONTENT_NONE
no type for content
Definition: content_type.h:55
content_msg
Used in callbacks to indicate what has occurred.
Definition: content_type.h:105
@ CONTENT_MSG_DONE
content has finished processing
Definition: content_type.h:119
@ CONTENT_MSG_DOWNLOAD
download, not for display
Definition: content_type.h:140
@ CONTENT_MSG_LOADING
fetching or converting
Definition: content_type.h:113
@ CONTENT_MSG_ERROR
error occurred
Definition: content_type.h:122
@ CONTENT_MSG_REDIRECT
fetch url redirect occured
Definition: content_type.h:125
@ CONTENT_MSG_SSL_CERTS
Content is from SSL and this is its chain.
Definition: content_type.h:110
@ CONTENT_MSG_READY
may be displayed
Definition: content_type.h:116
nserror
Enumeration of error codes.
Definition: errors.h:29
@ NSERROR_NOT_FOUND
Requested item not found.
Definition: errors.h:34
@ NSERROR_NEED_DATA
More data needed.
Definition: errors.h:46
@ NSERROR_UNKNOWN
Unknown error - DO NOT USE.
Definition: errors.h:31
@ NSERROR_NOMEM
Memory exhaustion.
Definition: errors.h:32
@ NSERROR_CLONE_FAILED
Failed to clone handle.
Definition: errors.h:37
@ NSERROR_OK
No error.
Definition: errors.h:30
const char * type
Definition: filetype.cpp:44
struct netsurf_table * guit
The global interface table.
Definition: gui_factory.c:50
Interface to core interface table.
static bool hlcache_type_is_acceptable(lwc_string *mime_type, content_type accepted_types, content_type *computed_type)
Determine if the specified MIME type is acceptable.
Definition: hlcache.c:171
nserror hlcache_initialise(const struct hlcache_parameters *hlcache_parameters)
Initialise the high-level cache, preparing the llcache also.
Definition: hlcache.c:548
static nserror hlcache_migrate_ctx(hlcache_retrieval_ctx *ctx, lwc_string *effective_type)
Migrate a retrieval context into its final destination content.
Definition: hlcache.c:348
static void hlcache_clean(void *force_clean_flag)
Attempt to clean the cache.
Definition: hlcache.c:111
struct content * hlcache_handle_get_content(const hlcache_handle *handle)
Retrieve a content object from a cache handle.
Definition: hlcache.c:772
static void hlcache_content_callback(struct content *c, content_msg msg, const union content_msg_data *data, void *pw)
Veneer between content callback API and hlcache callback API.
Definition: hlcache.c:191
nsurl * hlcache_handle_get_url(const hlcache_handle *handle)
Definition: hlcache.c:872
void hlcache_finalise(void)
Finalise the high-level cache, destroying any remaining contents.
Definition: hlcache.c:580
void hlcache_stop(void)
Stop the high-level cache periodic functionality so that the exit sequence can run.
Definition: hlcache.c:573
static nserror hlcache_find_content(hlcache_retrieval_ctx *ctx, lwc_string *effective_type)
Find a content for the high-level cache handle.
Definition: hlcache.c:225
static nserror hlcache_llcache_callback(llcache_handle *handle, const llcache_event *event, void *pw)
Handler for low-level cache events.
Definition: hlcache.c:429
nserror hlcache_handle_abort(hlcache_handle *handle)
Abort a high-level cache fetch.
Definition: hlcache.c:782
static struct hlcache_s * hlcache
high level cache state
Definition: hlcache.c:100
nserror hlcache_handle_clone(hlcache_handle *handle, hlcache_handle **result)
Clone a high level cache handle.
Definition: hlcache.c:865
nserror hlcache_handle_replace_callback(hlcache_handle *handle, hlcache_handle_callback cb, void *pw)
Replace a high-level cache handle's callback.
Definition: hlcache.c:856
nserror hlcache_handle_release(hlcache_handle *handle)
Release a high-level cache handle.
Definition: hlcache.c:736
nserror hlcache_handle_retrieve(nsurl *url, uint32_t flags, nsurl *referer, llcache_post_data *post, hlcache_handle_callback cb, void *pw, hlcache_child_context *child, content_type accepted_types, hlcache_handle **result)
Retrieve a high-level cache handle for an object.
Definition: hlcache.c:675
High-level resource cache interface.
nserror(* hlcache_handle_callback)(hlcache_handle *handle, const hlcache_event *event, void *pw)
Client callback for high-level cache events.
Definition: hlcache.h:63
@ HLCACHE_RETRIEVE_SNIFF_TYPE
Definition: hlcache.h:75
@ HLCACHE_RETRIEVE_MAY_DOWNLOAD
It's permitted to convert this request into a download.
Definition: hlcache.h:73
HTTP header parsing functions.
Public content interface.
Interface to platform-specific miscellaneous browser operation table.
Netsurf additional integer type formatting macros.
nserror llcache_initialise(const struct llcache_parameters *prm)
Initialise the low-level cache.
Definition: llcache.c:3891
void llcache_clean(bool purge)
Cause the low-level cache to attempt to perform cleanup.
Definition: llcache.c:3725
nserror llcache_handle_abort(llcache_handle *handle)
Abort a low-level fetch, informing all users of this action.
Definition: llcache.c:4098
void llcache_finalise(void)
Finalise the low-level cache.
Definition: llcache.c:3916
bool llcache_handle_references_same_object(const llcache_handle *a, const llcache_handle *b)
Determine if the same underlying object is referenced by the given handles.
Definition: llcache.c:4229
nsurl * llcache_handle_get_url(const llcache_handle *handle)
Retrieve the post-redirect URL of a low-level cache object.
Definition: llcache.c:4195
const char * llcache_handle_get_header(const llcache_handle *handle, const char *key)
Retrieve a header value associated with a low-level cache object.
Definition: llcache.c:4210
nserror llcache_handle_retrieve(nsurl *url, uint32_t flags, nsurl *referer, const llcache_post_data *post, llcache_handle_callback cb, void *pw, llcache_handle **result)
Retrieve a handle for a low-level cache object.
Definition: llcache.c:3990
nserror llcache_handle_force_stream(llcache_handle *handle)
Force a low-level cache handle into streaming mode.
Definition: llcache.c:4160
nserror llcache_handle_release(llcache_handle *handle)
Release a low-level cache handle.
Definition: llcache.c:4058
@ LLCACHE_EVENT_DONE
Finished fetching data.
Definition: llcache.h:71
@ LLCACHE_EVENT_ERROR
An error occurred during fetch.
Definition: llcache.h:73
@ LLCACHE_EVENT_GOT_CERTS
SSL certificates arrived.
Definition: llcache.h:68
@ LLCACHE_EVENT_REDIRECT
Fetch URL redirect occured.
Definition: llcache.h:76
@ LLCACHE_EVENT_PROGRESS
Fetch progress update.
Definition: llcache.h:74
@ LLCACHE_EVENT_HAD_HEADERS
Received all headers.
Definition: llcache.h:69
@ LLCACHE_EVENT_HAD_DATA
Received some data.
Definition: llcache.h:70
#define NSLOG(catname, level, logmsg, args...)
Definition: log.h:116
const char * messages_get(const char *key)
Fast lookup of a message by key from the standard Messages hash.
Definition: messages.c:256
Localised message support (interface).
nserror mimesniff_compute_effective_type(const char *content_type_header, const uint8_t *data, size_t len, bool sniff_allowed, bool image_only, lwc_string **effective_type)
Compute the effective MIME type for an object.
Definition: mimesniff.c:563
MIME type sniffer interface.
const char * nsurl_access(const nsurl *url)
Access a NetSurf URL object as a string.
struct nsurl nsurl
NetSurf URL object.
Definition: nsurl.h:31
Ring list structure.
#define RING_ITERATE_STOP(ring, iteratorptr)
Definition: ring.h:133
#define RING_REMOVE(ring, element)
Remove the given element from the specified ring.
Definition: ring.h:53
#define RING_INSERT(ring, element)
Insert the given item into the specified ring.
Definition: ring.h:40
#define RING_ITERATE_END(ring, iteratorptr)
Definition: ring.h:136
#define RING_ITERATE_START(ringtype, ring, iteratorptr)
Definition: ring.h:127
Interface to utility string handling.
Content which corresponds to a single URL.
nserror(* schedule)(int t, void(*callback)(void *p), void *p)
Schedule a callback.
Definition: misc.h:58
Context for retrieving a child object.
Definition: hlcache.h:37
bool quirks
Whether parent is quirky.
Definition: hlcache.h:39
const char * charset
Charset of parent.
Definition: hlcache.h:38
Entry in high-level cache.
Definition: hlcache.c:74
hlcache_entry * next
Next sibling.
Definition: hlcache.c:77
hlcache_entry * prev
Previous sibling.
Definition: hlcache.c:78
struct content * content
Pointer to associated content.
Definition: hlcache.c:75
High-level cache event.
Definition: hlcache.h:43
content_msg type
Event type.
Definition: hlcache.h:44
union content_msg_data data
Event data.
Definition: hlcache.h:45
High-level cache handle.
Definition: hlcache.c:66
hlcache_handle_callback cb
Client callback.
Definition: hlcache.c:69
void * pw
Client data.
Definition: hlcache.c:70
hlcache_entry * entry
Pointer to cache entry.
Definition: hlcache.c:67
unsigned int bg_clean_time
How frequently the background cache clean process is run (ms)
Definition: hlcache.h:50
struct llcache_parameters llcache
Definition: hlcache.h:52
High-level cache retrieval context.
Definition: hlcache.c:48
hlcache_child_context child
Child context.
Definition: hlcache.c:60
llcache_handle * llcache
Low-level cache handle.
Definition: hlcache.c:52
struct hlcache_retrieval_ctx * r_next
Next retrieval context in the ring.
Definition: hlcache.c:50
bool migrate_target
Whether this context is the migration target.
Definition: hlcache.c:62
struct hlcache_retrieval_ctx * r_prev
Previous retrieval context in the ring.
Definition: hlcache.c:49
content_type accepted_types
Accepted types.
Definition: hlcache.c:58
uint32_t flags
Retrieval flags.
Definition: hlcache.c:56
hlcache_handle * handle
High-level handle for object.
Definition: hlcache.c:54
Current state of the cache.
Definition: hlcache.c:85
hlcache_retrieval_ctx * retrieval_ctx_ring
Ring of retrieval contexts.
Definition: hlcache.c:92
struct hlcache_parameters params
Definition: hlcache.c:86
hlcache_entry * content_list
List of cached content objects.
Definition: hlcache.c:89
unsigned int hit_count
Definition: hlcache.c:95
unsigned int miss_count
Definition: hlcache.c:96
Low-level cache events.
Definition: llcache.h:85
struct llcache_event::@124::@125 data
Received data.
size_t len
Byte length of buffer.
Definition: llcache.h:90
llcache_event_type type
Type of event.
Definition: llcache.h:86
const uint8_t * buf
Buffer of data.
Definition: llcache.h:89
Handle to low-level cache object.
Definition: llcache.c:76
POST data object for low-level cache requests.
Definition: llcache.h:40
struct gui_misc_table * misc
Browser table.
Definition: gui_table.h:57
Extra data for some content_msg messages.
Definition: content.h:60
struct content_msg_data::@99 errordata
CONTENT_MSG_ERROR - Error from content or underlying fetch.
nserror errorcode
The error code to convey meaning.
Definition: content.h:88
const char * errormsg
The message.
Definition: content.h:95
const struct cert_chain * chain
CONTENT_MSG_SSL_CERTS - The certificate chain from the underlying fetch.
Definition: content.h:79
struct nsurl * to
Redirect target.
Definition: content.h:103
struct nsurl * from
Redirect origin.
Definition: content.h:102
struct llcache_handle * download
CONTENT_MSG_DOWNLOAD - Low-level cache handle.
Definition: content.h:133
struct content_msg_data::@100 redirect
CONTENT_MSG_REDIRECT - Redirect info.
Interface to a number of general purpose functionality.