Dillo v3.1.1-46-g8a360e32
Loading...
Searching...
No Matches
cache.c
Go to the documentation of this file.
1/*
2 * File: cache.c
3 *
4 * Copyright 2000-2007 Jorge Arellano Cid <jcid@dillo.org>
5 * Copyright 2024 Rodrigo Arias Mallo <rodarima@gmail.com>
6 *
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 */
12
13/*
14 * @file
15 * Dillo's cache module
16 */
17
18#include <sys/types.h>
19
20#include <limits.h>
21#include <stdlib.h>
22#include <string.h>
23
24#include "msg.h"
25#include "IO/Url.h"
26#include "IO/IO.h"
27#include "web.hh"
28#include "dicache.h"
29#include "nav.h"
30#include "cookies.h"
31#include "hsts.h"
32#include "misc.h"
33#include "capi.h"
34#include "decode.h"
35#include "auth.h"
36#include "domain.h"
37#include "timeout.hh"
38#include "uicmd.hh"
39
41#define MAX_INIT_BUF 1024*1024
43#define HUGE_FILESIZE 15*1024*1024
44
45/*
46 * Local data types
47 */
48
49typedef struct {
50 const DilloUrl *Url;
51 char *TypeDet;
52 char *TypeHdr;
53 char *TypeMeta;
54 char *TypeNorm;
55 Dstr *Header;
56 const DilloUrl *Location;
57 Dlist *Auth;
58 Dstr *Data;
59 Dstr *UTF8Data;
60 int DataRefcount;
61 DecodeTransfer *TransferDecoder;
62 Decode *ContentDecoder;
63 Decode *CharsetDecoder;
64 int ExpectedSize;
65 int TransferSize;
66 uint_t Flags;
67} CacheEntry_t;
68
69
70/*
71 * Local data
72 */
75
79
84
85
86/*
87 * Forward declarations
88 */
89static CacheEntry_t *Cache_process_queue(CacheEntry_t *entry);
90static void Cache_delayed_process_queue(CacheEntry_t *entry);
91static void Cache_auth_entry(CacheEntry_t *entry, BrowserWindow *bw);
92static void Cache_entry_inject(const DilloUrl *Url, Dstr *data_ds);
93
97static int Cache_entry_cmp(const void *v1, const void *v2)
98{
99 const CacheEntry_t *d1 = v1, *d2 = v2;
100
101 return a_Url_cmp(d1->Url, d2->Url);
102}
103
107static int Cache_entry_by_url_cmp(const void *v1, const void *v2)
108{
109 const DilloUrl *u1 = ((CacheEntry_t*)v1)->Url;
110 const DilloUrl *u2 = v2;
111
112 return a_Url_cmp(u1, u2);
113}
114
118void a_Cache_init(void)
119{
122 CachedURLs = dList_new(256);
123
124 /* inject the splash screen in the cache */
125 {
126 DilloUrl *url = a_Url_new("about:splash", NULL);
128 Cache_entry_inject(url, ds);
129 dStr_free(ds, 1);
130 a_Url_free(url);
131 }
132}
133
134/* Client operations ------------------------------------------------------ */
135
141static int Cache_client_enqueue(const DilloUrl *Url, DilloWeb *Web,
142 CA_Callback_t Callback, void *CbData)
143{
144 static int ClientKey = 0; /* Provide a primary key for each client */
145 CacheClient_t *NewClient;
146
147 if (ClientKey < INT_MAX) /* check for integer overflow */
148 ClientKey++;
149 else
150 ClientKey = 1;
151
152 NewClient = dNew(CacheClient_t, 1);
153 NewClient->Key = ClientKey;
154 NewClient->Url = Url;
155 NewClient->Version = 0;
156 NewClient->Buf = NULL;
157 NewClient->BufSize = 0;
158 NewClient->Callback = Callback;
159 NewClient->CbData = CbData;
160 NewClient->Web = Web;
161
162 dList_append(ClientQueue, NewClient);
163
164 return ClientKey;
165}
166
170static int Cache_client_by_key_cmp(const void *client, const void *key)
171{
172 return ((CacheClient_t *)client)->Key - VOIDP2INT(key);
173}
174
179{
180 if (Client) {
181 dList_remove(ClientQueue, Client);
182 a_Web_free(Client->Web);
183 dFree(Client);
184 }
185}
186
187
188/* Entry operations ------------------------------------------------------- */
189
193static void Cache_entry_init(CacheEntry_t *NewEntry, const DilloUrl *Url)
194{
195 NewEntry->Url = a_Url_dup(Url);
196 NewEntry->TypeDet = NULL;
197 NewEntry->TypeHdr = NULL;
198 NewEntry->TypeMeta = NULL;
199 NewEntry->TypeNorm = NULL;
200 NewEntry->Header = dStr_new("");
201 NewEntry->Location = NULL;
202 NewEntry->Auth = NULL;
203 NewEntry->Data = dStr_sized_new(8*1024);
204 NewEntry->UTF8Data = NULL;
205 NewEntry->DataRefcount = 0;
206 NewEntry->TransferDecoder = NULL;
207 NewEntry->ContentDecoder = NULL;
208 NewEntry->CharsetDecoder = NULL;
209 NewEntry->ExpectedSize = 0;
210 NewEntry->TransferSize = 0;
211 NewEntry->Flags = CA_IsEmpty | CA_InProgress | CA_KeepAlive;
212}
213
218static CacheEntry_t *Cache_entry_search(const DilloUrl *Url)
219{
221}
222
226static CacheEntry_t *Cache_entry_search_with_redirect(const DilloUrl *Url)
227{
228 int i;
229 CacheEntry_t *entry;
230
231 for (i = 0; (entry = Cache_entry_search(Url)); ++i) {
232
233 /* Test for a redirection loop */
234 if (entry->Flags & CA_RedirectLoop || i == 3) {
235 _MSG_WARN("Redirect loop for URL: >%s<\n", URL_STR_(Url));
236 break;
237 }
238 /* Test for a working redirection */
239 if (entry->Flags & CA_Redirect && entry->Location) {
240 Url = entry->Location;
241 } else
242 break;
243 }
244 return entry;
245}
246
250static CacheEntry_t *Cache_entry_add(const DilloUrl *Url)
251{
252 CacheEntry_t *old_entry, *new_entry;
253
254 if ((old_entry = Cache_entry_search(Url))) {
255 MSG_WARN("Cache_entry_add, leaking an entry.\n");
256 dList_remove(CachedURLs, old_entry);
257 }
258
259 new_entry = dNew(CacheEntry_t, 1);
260 Cache_entry_init(new_entry, Url); /* Set safe values */
262 return new_entry;
263}
264
269static void Cache_entry_inject(const DilloUrl *Url, Dstr *data_ds)
270{
271 CacheEntry_t *entry;
272
273 if (!(entry = Cache_entry_search(Url)))
274 entry = Cache_entry_add(Url);
275 entry->Flags = CA_GotHeader + CA_GotLength + CA_InternalUrl;
276 if (data_ds->len)
277 entry->Flags &= ~CA_IsEmpty;
278 dStr_truncate(entry->Data, 0);
279 dStr_append_l(entry->Data, data_ds->str, data_ds->len);
280 dStr_fit(entry->Data);
281 entry->ExpectedSize = entry->TransferSize = entry->Data->len;
282}
283
287static void Cache_auth_free(Dlist *auth)
288{
289 int i;
290 void *auth_field;
291 for (i = 0; (auth_field = dList_nth_data(auth, i)); ++i)
292 dFree(auth_field);
293 dList_free(auth);
294}
295
299static void Cache_entry_free(CacheEntry_t *entry)
300{
301 a_Url_free((DilloUrl *)entry->Url);
302 dFree(entry->TypeDet);
303 dFree(entry->TypeHdr);
304 dFree(entry->TypeMeta);
305 dFree(entry->TypeNorm);
306 dStr_free(entry->Header, TRUE);
307 a_Url_free((DilloUrl *)entry->Location);
308 Cache_auth_free(entry->Auth);
309 dStr_free(entry->Data, 1);
310 dStr_free(entry->UTF8Data, 1);
311 if (entry->CharsetDecoder)
312 a_Decode_free(entry->CharsetDecoder);
313 if (entry->TransferDecoder)
314 a_Decode_transfer_free(entry->TransferDecoder);
315 if (entry->ContentDecoder)
316 a_Decode_free(entry->ContentDecoder);
317 dFree(entry);
318}
319
325static void Cache_entry_remove(CacheEntry_t *entry, DilloUrl *url)
326{
327 int i;
328 CacheClient_t *Client;
329
330 if (!entry && !(entry = Cache_entry_search(url)))
331 return;
332 if (entry->Flags & CA_InternalUrl)
333 return;
334
335 /* remove all clients for this entry */
336 for (i = 0; (Client = dList_nth_data(ClientQueue, i)); ++i) {
337 if (Client->Url == entry->Url) {
338 a_Cache_stop_client(Client->Key);
339 --i;
340 }
341 }
342
343 /* remove from DelayedQueue */
345
346 /* remove from dicache */
347 a_Dicache_invalidate_entry(entry->Url);
348
349 /* remove from cache */
350 dList_remove(CachedURLs, entry);
351 Cache_entry_free(entry);
352}
353
358{
359 Cache_entry_remove(NULL, url);
360}
361
362/* Misc. operations ------------------------------------------------------- */
363
376int a_Cache_open_url(void *web, CA_Callback_t Call, void *CbData)
377{
378 int ClientKey;
379 CacheEntry_t *entry;
380 DilloWeb *Web = web;
381 DilloUrl *Url = Web->url;
382
383 if (URL_FLAGS(Url) & URL_E2EQuery) {
384 /* remove current entry */
385 Cache_entry_remove(NULL, Url);
386 }
387
388 if ((entry = Cache_entry_search(Url))) {
389 /* URL is cached: feed our client with cached data */
390 ClientKey = Cache_client_enqueue(entry->Url, Web, Call, CbData);
392
393 } else {
394 /* URL not cached: create an entry, send our client to the queue,
395 * and open a new connection */
396 entry = Cache_entry_add(Url);
397 ClientKey = Cache_client_enqueue(entry->Url, Web, Call, CbData);
398 }
399
400 return ClientKey;
401}
402
407{
408 CacheEntry_t *entry = Cache_entry_search(url);
409 return (entry ? entry->Flags : 0);
410}
411
416{
417 CacheEntry_t *entry = Cache_entry_search_with_redirect(url);
418 return (entry ? entry->Flags : 0);
419}
420
424static void Cache_ref_data(CacheEntry_t *entry)
425{
426 if (entry) {
427 entry->DataRefcount++;
428 _MSG("DataRefcount++: %d\n", entry->DataRefcount);
429 if (entry->CharsetDecoder &&
430 (!entry->UTF8Data || entry->DataRefcount == 1)) {
431 dStr_free(entry->UTF8Data, 1);
432 entry->UTF8Data = a_Decode_process(entry->CharsetDecoder,
433 entry->Data->str,
434 entry->Data->len);
435 }
436 }
437}
438
442static void Cache_unref_data(CacheEntry_t *entry)
443{
444 if (entry) {
445 entry->DataRefcount--;
446 _MSG("DataRefcount--: %d\n", entry->DataRefcount);
447
448 if (entry->CharsetDecoder) {
449 if (entry->DataRefcount == 0) {
450 dStr_free(entry->UTF8Data, 1);
451 entry->UTF8Data = NULL;
452 } else if (entry->DataRefcount < 0) {
453 MSG_ERR("Cache_unref_data: negative refcount\n");
454 entry->DataRefcount = 0;
455 }
456 }
457 }
458}
459
463static const char *Cache_current_content_type(CacheEntry_t *entry)
464{
465 return entry->TypeNorm ? entry->TypeNorm : entry->TypeMeta ? entry->TypeMeta
466 : entry->TypeHdr ? entry->TypeHdr : entry->TypeDet;
467}
468
472const char *a_Cache_get_content_type(const DilloUrl *url)
473{
474 CacheEntry_t *entry = Cache_entry_search_with_redirect(url);
475
476 return (entry) ? Cache_current_content_type(entry) : NULL;
477}
478
482static Dstr *Cache_data(CacheEntry_t *entry)
483{
484 return entry->UTF8Data ? entry->UTF8Data : entry->Data;
485}
486
492const char *a_Cache_set_content_type(const DilloUrl *url, const char *ctype,
493 const char *from)
494{
495 const char *curr;
496 char *major, *minor, *charset;
497 CacheEntry_t *entry = Cache_entry_search(url);
498
499 dReturn_val_if_fail (entry != NULL, NULL);
500
501 _MSG("a_Cache_set_content_type {%s} {%s}\n", ctype, URL_STR(url));
502
503 curr = Cache_current_content_type(entry);
504 if (entry->TypeMeta || (*from == 'h' && entry->TypeHdr) ) {
505 /* Type is already been set. Do nothing.
506 * BTW, META overrides TypeHdr */
507 } else {
508 if (*from == 'h') {
509 /* Content-Type from HTTP header */
510 entry->TypeHdr = dStrdup(ctype);
511 } else {
512 /* Content-Type from META */
513 entry->TypeMeta = dStrdup(ctype);
514 }
515 if (a_Misc_content_type_cmp(curr, ctype)) {
516 /* ctype gives one different from current */
517 a_Misc_parse_content_type(ctype, &major, &minor, &charset);
518 if (*from == 'm' && charset &&
519 ((!major || !*major) && (!minor || !*minor))) {
520 /* META only gives charset; use detected MIME type too */
521 entry->TypeNorm = dStrconcat(entry->TypeDet, ctype, NULL);
522 } else if (*from == 'm' &&
523 !dStrnAsciiCasecmp(ctype, "text/xhtml", 10)) {
524 /* WORKAROUND: doxygen uses "text/xhtml" in META */
525 if (charset) {
526 entry->TypeNorm = dStrconcat("application/xhtml+xml",
527 "; charset=", charset, NULL);
528 } else {
529 entry->TypeNorm = dStrdup("application/xhtml+xml");
530 }
531 }
532 if (charset) {
533 if (entry->CharsetDecoder)
534 a_Decode_free(entry->CharsetDecoder);
535 entry->CharsetDecoder = a_Decode_charset_init(charset);
536 curr = Cache_current_content_type(entry);
537
538 /* Invalidate UTF8Data */
539 dStr_free(entry->UTF8Data, 1);
540 entry->UTF8Data = NULL;
541 }
542 dFree(major); dFree(minor); dFree(charset);
543 }
544 }
545 return curr;
546}
547
552int a_Cache_get_buf(const DilloUrl *Url, char **PBuf, int *BufSize)
553{
554 CacheEntry_t *entry = Cache_entry_search_with_redirect(Url);
555 if (entry) {
556 Dstr *data;
557 Cache_ref_data(entry);
558 data = Cache_data(entry);
559 *PBuf = data->str;
560 *BufSize = data->len;
561 } else {
562 *PBuf = NULL;
563 *BufSize = 0;
564 }
565 return (entry ? 1 : 0);
566}
567
575
576
583static char *Cache_parse_field(const char *header, const char *fieldname)
584{
585 char *field;
586 uint_t i, j;
587
588 for (i = 0; header[i]; i++) {
589 /* Search fieldname */
590 for (j = 0; fieldname[j]; j++)
591 if (D_ASCII_TOLOWER(fieldname[j]) != D_ASCII_TOLOWER(header[i + j]))
592 break;
593 if (fieldname[j]) {
594 /* skip to next line */
595 for ( i += j; header[i] != '\n'; i++);
596 continue;
597 }
598
599 i += j;
600 if (header[i] == ':') {
601 /* Field found! */
602 while (header[++i] == ' ' || header[i] == '\t');
603 for (j = 0; header[i + j] != '\n'; j++);
604 while (j && (header[i + j - 1] == ' ' || header[i + j - 1] == '\t'))
605 j--;
606 field = dStrndup(header + i, j);
607 return field;
608 }
609 while (header[i] != '\n') i++;
610 }
611 return NULL;
612}
613
617static Dlist *Cache_parse_multiple_fields(const char *header,
618 const char *fieldname)
619{
620 uint_t i, j;
621 Dlist *fields = dList_new(8);
622 char *field;
623
624 for (i = 0; header[i]; i++) {
625 /* Search fieldname */
626 for (j = 0; fieldname[j]; j++)
627 if (D_ASCII_TOLOWER(fieldname[j]) != D_ASCII_TOLOWER(header[i + j]))
628 break;
629 if (fieldname[j]) {
630 /* skip to next line */
631 for (i += j; header[i] != '\n'; i++);
632 continue;
633 }
634
635 i += j;
636 if (header[i] == ':') {
637 /* Field found! */
638 while (header[++i] == ' ' || header[i] == '\t');
639 for (j = 0; header[i + j] != '\n'; j++);
640 while (j && (header[i + j - 1] == ' ' || header[i + j - 1] == '\t'))
641 j--;
642 field = dStrndup(header + i, j);
643 dList_append(fields, field);
644 } else {
645 while (header[i] != '\n') i++;
646 }
647 }
648
649 if (dList_length(fields) == 0) {
650 dList_free(fields);
651 fields = NULL;
652 }
653 return fields;
654}
655
660static void Cache_parse_header(CacheEntry_t *entry)
661{
662 char *header = entry->Header->str;
663 bool_t server1point0 = !strncmp(entry->Header->str, "HTTP/1.0", 8);
664 char *Length, *Type, *location_str, *encoding, *connection, *hsts;
665#ifndef DISABLE_COOKIES
666 Dlist *Cookies;
667#endif
668 Dlist *warnings;
669 void *data;
670 int i;
671
672 _MSG("Cache_parse_header\n");
673
674 if (entry->Header->len > 12) {
675 if (header[9] == '1' && header[10] == '0' && header[11] == '0') {
676 /* 100: Continue. The "real" header has not come yet. */
677 MSG("An actual 100 Continue header!\n");
678 entry->Flags &= ~CA_GotHeader;
679 dStr_free(entry->Header, 1);
680 entry->Header = dStr_new("");
681 return;
682 }
683 if (header[9] == '3' && header[10] == '0' &&
684 (location_str = Cache_parse_field(header, "Location"))) {
685 /* 30x: URL redirection */
686 entry->Location = a_Url_new(location_str, URL_STR_(entry->Url));
687
688 if (!a_Domain_permit(entry->Url, entry->Location) ||
689 (URL_FLAGS(entry->Location) & (URL_Post + URL_Get) &&
690 dStrAsciiCasecmp(URL_SCHEME(entry->Location), "dpi") == 0 &&
691 dStrAsciiCasecmp(URL_SCHEME(entry->Url), "dpi") != 0)) {
692 /* Domain test, and forbid dpi GET and POST from non dpi-generated
693 * urls.
694 */
695 MSG("Redirection not followed from %s to %s\n",
696 URL_HOST(entry->Url), URL_STR(entry->Location));
697 } else {
698 entry->Flags |= CA_Redirect;
699 if (header[11] == '1')
700 entry->Flags |= CA_ForceRedirect; /* 301 Moved Permanently */
701 else if (header[11] == '2')
702 entry->Flags |= CA_TempRedirect; /* 302 Temporary Redirect */
703 }
704 dFree(location_str);
705 } else if (strncmp(header + 9, "401", 3) == 0) {
706 entry->Auth =
707 Cache_parse_multiple_fields(header, "WWW-Authenticate");
708 } else if (strncmp(header + 9, "404", 3) == 0) {
709 entry->Flags |= CA_NotFound;
710 }
711 }
712
713 if ((warnings = Cache_parse_multiple_fields(header, "Warning"))) {
714 for (i = 0; (data = dList_nth_data(warnings, i)); ++i) {
715 MSG_HTTP("%s\n", (char *)data);
716 dFree(data);
717 }
718 dList_free(warnings);
719 }
720
721 if (server1point0)
722 entry->Flags &= ~CA_KeepAlive;
723
724 if ((connection = Cache_parse_field(header, "Connection"))) {
725 if (!dStrAsciiCasecmp(connection, "close"))
726 entry->Flags &= ~CA_KeepAlive;
727 else if (server1point0 && !dStrAsciiCasecmp(connection, "keep-alive"))
728 entry->Flags |= CA_KeepAlive;
729 dFree(connection);
730 }
731
733 !dStrAsciiCasecmp(URL_SCHEME(entry->Url), "https") &&
734 a_Url_host_type(URL_HOST(entry->Url)) == URL_HOST_NAME &&
735 (hsts = Cache_parse_field(header, "Strict-Transport-Security"))) {
736 a_Hsts_set(hsts, entry->Url);
737 dFree(hsts);
738 }
739
740 /*
741 * Get Transfer-Encoding and initialize decoder
742 */
743 encoding = Cache_parse_field(header, "Transfer-Encoding");
744 entry->TransferDecoder = a_Decode_transfer_init(encoding);
745
746
747 if ((Length = Cache_parse_field(header, "Content-Length")) != NULL) {
748 if (encoding) {
749 /*
750 * If Transfer-Encoding is present, Content-Length must be ignored.
751 * If the Transfer-Encoding is non-identity, it is an error.
752 */
753 if (dStrAsciiCasecmp(encoding, "identity"))
754 MSG_HTTP("Content-Length and non-identity Transfer-Encoding "
755 "headers both present.\n");
756 } else {
757 entry->Flags |= CA_GotLength;
758 entry->ExpectedSize = MAX(strtol(Length, NULL, 10), 0);
759 }
760 dFree(Length);
761 }
762
763 dFree(encoding); /* free Transfer-Encoding */
764
765#ifndef DISABLE_COOKIES
766 if ((Cookies = Cache_parse_multiple_fields(header, "Set-Cookie"))) {
767 CacheClient_t *client;
768
769 for (i = 0; (client = dList_nth_data(ClientQueue, i)); ++i) {
770 if (client->Url == entry->Url) {
771 DilloWeb *web = client->Web;
772
773 if (!web->requester ||
774 a_Url_same_organization(entry->Url, web->requester)) {
775 /* If cookies are third party, don't even consider them. */
776 char *server_date = Cache_parse_field(header, "Date");
777
778 a_Cookies_set(Cookies, entry->Url, server_date);
779 dFree(server_date);
780 break;
781 }
782 }
783 }
784 for (i = 0; (data = dList_nth_data(Cookies, i)); ++i)
785 dFree(data);
786 dList_free(Cookies);
787 }
788#endif /* !DISABLE_COOKIES */
789
790 /*
791 * Get Content-Encoding and initialize decoder
792 */
793 encoding = Cache_parse_field(header, "Content-Encoding");
794 entry->ContentDecoder = a_Decode_content_init(encoding);
795 dFree(encoding);
796
797 if (entry->ExpectedSize > 0) {
798 if (entry->ExpectedSize > HUGE_FILESIZE) {
799 entry->Flags |= CA_HugeFile;
800 }
801 /* Avoid some reallocs. With MAX_INIT_BUF we avoid a SEGFAULT
802 * with huge files (e.g. iso files).
803 * Note: the buffer grows automatically. */
804 dStr_free(entry->Data, 1);
805 entry->Data = dStr_sized_new(MIN(entry->ExpectedSize, MAX_INIT_BUF));
806 }
807
808 /* Get Content-Type */
809 if ((Type = Cache_parse_field(header, "Content-Type"))) {
810 /* This HTTP Content-Type is not trusted. It's checked against real data
811 * in Cache_process_queue(); only then CA_GotContentType becomes true. */
812 a_Cache_set_content_type(entry->Url, Type, "http");
813 _MSG("TypeHdr {%s} {%s}\n", Type, URL_STR(entry->Url));
814 _MSG("TypeMeta {%s}\n", entry->TypeMeta);
815 dFree(Type);
816 }
817 Cache_ref_data(entry);
818}
819
824static int Cache_get_header(CacheEntry_t *entry,
825 const char *buf, size_t buf_size)
826{
827 size_t N, i;
828 Dstr *hdr = entry->Header;
829
830 /* Header finishes when N = 2 */
831 N = (hdr->len && hdr->str[hdr->len - 1] == '\n');
832 for (i = 0; i < buf_size && N < 2; ++i) {
833 if (buf[i] == '\r' || !buf[i])
834 continue;
835 if (N == 1 && (buf[i] == ' ' || buf[i] == '\t')) {
836 /* unfold multiple-line header */
837 _MSG("Multiple-line header!\n");
838 dStr_erase(hdr, hdr->len - 1, 1);
839 }
840 N = (buf[i] == '\n') ? N + 1 : 0;
841 dStr_append_c(hdr, buf[i]);
842 }
843
844 if (N == 2) {
845 /* Got whole header */
846 _MSG("Header [buf_size=%d]\n%s", i, hdr->str);
847 entry->Flags |= CA_GotHeader;
848 dStr_fit(hdr);
849 /* Return number of header bytes in 'buf' [1 based] */
850 return i;
851 }
852 return 0;
853}
854
855static void Cache_finish_msg(CacheEntry_t *entry)
856{
857 if (!(entry->Flags & CA_InProgress)) {
858 /* already finished */
859 return;
860 }
861
862 if ((entry->ExpectedSize || entry->TransferSize) &&
863 entry->TypeHdr == NULL) {
864 MSG_HTTP("Message with a body lacked Content-Type header.\n");
865 }
866 if ((entry->Flags & CA_GotLength) &&
867 (entry->ExpectedSize != entry->TransferSize)) {
868 MSG_HTTP("Content-Length (%d) does NOT match message body (%d) for %s\n",
869 entry->ExpectedSize, entry->TransferSize, URL_STR_(entry->Url));
870 }
871 entry->Flags &= ~CA_InProgress;
872 if (entry->TransferDecoder) {
873 a_Decode_transfer_free(entry->TransferDecoder);
874 entry->TransferDecoder = NULL;
875 }
876 if (entry->ContentDecoder) {
877 a_Decode_free(entry->ContentDecoder);
878 entry->ContentDecoder = NULL;
879 }
880 dStr_fit(entry->Data); /* fit buffer size! */
881
882 if ((entry = Cache_process_queue(entry))) {
883 if (entry->Flags & CA_GotHeader) {
884 Cache_unref_data(entry);
885 }
886 }
887}
888
897bool_t a_Cache_process_dbuf(int Op, const char *buf, size_t buf_size,
898 const DilloUrl *Url)
899{
900 int offset, len;
901 const char *str;
902 Dstr *dstr1, *dstr2, *dstr3;
903 bool_t done = FALSE;
904 CacheEntry_t *entry = Cache_entry_search(Url);
905
906 /* Assert a valid entry (not aborted) */
907 dReturn_val_if_fail (entry != NULL, FALSE);
908
909 _MSG("__a_Cache_process_dbuf__\n");
910
911 if (Op == IORead) {
912 /*
913 * Cache_get_header() will set CA_GotHeader if it has a full header, and
914 * Cache_parse_header() will unset it if the header ends being
915 * merely an informational response from the server (i.e., 100 Continue)
916 */
917 for (offset = 0; !(entry->Flags & CA_GotHeader) &&
918 (len = Cache_get_header(entry, buf + offset, buf_size - offset));
919 Cache_parse_header(entry) ) {
920 offset += len;
921 }
922
923 if (entry->Flags & CA_GotHeader) {
924 str = buf + offset;
925 len = buf_size - offset;
926 entry->TransferSize += len;
927 dstr1 = dstr2 = dstr3 = NULL;
928
929 /* Decode arrived data (<= 3 stages) */
930 if (entry->TransferDecoder) {
931 dstr1 = a_Decode_transfer_process(entry->TransferDecoder, str,len);
932 done = a_Decode_transfer_finished(entry->TransferDecoder);
933 str = dstr1->str;
934 len = dstr1->len;
935 }
936 if (entry->ContentDecoder) {
937 dstr2 = a_Decode_process(entry->ContentDecoder, str, len);
938 str = dstr2->str;
939 len = dstr2->len;
940 }
941 dStr_append_l(entry->Data, str, len);
942 if (entry->CharsetDecoder && entry->UTF8Data) {
943 dstr3 = a_Decode_process(entry->CharsetDecoder, str, len);
944 dStr_append_l(entry->UTF8Data, dstr3->str, dstr3->len);
945 }
946 dStr_free(dstr1, 1);
947 dStr_free(dstr2, 1);
948 dStr_free(dstr3, 1);
949
950 if (entry->Data->len)
951 entry->Flags &= ~CA_IsEmpty;
952
953 if ((entry->Flags & CA_GotLength) &&
954 (entry->TransferSize >= entry->ExpectedSize)) {
955 done = TRUE;
956 }
957 if (!(entry->Flags & CA_KeepAlive)) {
958 /* Let IOClose finish it later */
959 done = FALSE;
960 }
961
962 entry = Cache_process_queue(entry);
963
964 if (entry && done)
965 Cache_finish_msg(entry);
966 }
967 } else if (Op == IOClose) {
968 Cache_finish_msg(entry);
969 } else if (Op == IOAbort) {
970 entry->Flags |= CA_Aborted;
971 if (entry->Data->len) {
972 MSG("Premature close for %s\n", URL_STR(entry->Url));
973 Cache_finish_msg(entry);
974 } else {
975 int i;
976 CacheClient_t *Client;
977
978 for (i = 0; (Client = dList_nth_data(ClientQueue, i)); ++i) {
979 if (Client->Url == entry->Url) {
980 DilloWeb *web = (DilloWeb *)Client->Web;
981
982 a_Bw_remove_client(web->bw, Client->Key);
983 Cache_client_dequeue(Client);
984 --i; /* Keep the index value in the next iteration */
985 }
986 }
987 }
988 }
989 return done;
990}
991
996static int Cache_redirect(CacheEntry_t *entry, int Flags, BrowserWindow *bw)
997{
998 DilloUrl *NewUrl;
999
1000 _MSG(" Cache_redirect: redirect_level = %d\n", bw->redirect_level);
1001
1002 /* Don't allow redirection for SpamSafe/local URLs */
1003 if (URL_FLAGS(entry->Url) & URL_SpamSafe) {
1004 a_UIcmd_set_msg(bw, "WARNING: local URL with redirection. Aborting.");
1005 return 0;
1006 }
1007
1008 /* if there's a redirect loop, stop now */
1009 if (bw->redirect_level >= 5)
1010 entry->Flags |= CA_RedirectLoop;
1011
1012 if (entry->Flags & CA_RedirectLoop) {
1013 a_UIcmd_set_msg(bw, "ERROR: redirect loop for: %s", URL_STR_(entry->Url));
1014 bw->redirect_level = 0;
1015 return 0;
1016 }
1017
1018 if ((entry->Flags & CA_Redirect && entry->Location) &&
1019 (entry->Flags & CA_ForceRedirect || entry->Flags & CA_TempRedirect ||
1020 !entry->Data->len || entry->Data->len < 1024)) {
1021
1022 _MSG(">>>> Redirect from: %s\n to %s <<<<\n",
1023 URL_STR_(entry->Url), URL_STR_(entry->Location));
1024 _MSG("%s", entry->Header->str);
1025
1026 if (Flags & WEB_RootUrl) {
1027 /* Redirection of the main page */
1028 NewUrl = a_Url_new(URL_STR_(entry->Location), URL_STR_(entry->Url));
1029 if (entry->Flags & CA_TempRedirect)
1030 a_Url_set_flags(NewUrl, URL_FLAGS(NewUrl) | URL_E2EQuery);
1031 a_Nav_push(bw, NewUrl, entry->Url);
1032 a_Url_free(NewUrl);
1033 } else {
1034 /* Sub entity redirection (most probably an image) */
1035 if (!entry->Data->len) {
1036 _MSG(">>>> Image redirection without entity-content <<<<\n");
1037 } else {
1038 _MSG(">>>> Image redirection with entity-content <<<<\n");
1039 }
1040 }
1041 }
1042 return 0;
1043}
1044
1045typedef struct {
1046 Dlist *auth;
1047 DilloUrl *url;
1048 BrowserWindow *bw;
1049} CacheAuthData_t;
1050
1054static void Cache_auth_callback(void *vdata)
1055{
1056 CacheAuthData_t *data = (CacheAuthData_t *)vdata;
1057 if (a_Auth_do_auth(data->auth, data->url))
1058 a_Nav_reload(data->bw);
1059 Cache_auth_free(data->auth);
1060 a_Url_free(data->url);
1061 dFree(data);
1062 Cache_auth_entry(NULL, NULL);
1064}
1065
1069static void Cache_auth_entry(CacheEntry_t *entry, BrowserWindow *bw)
1070{
1071 static int busy = 0;
1072 CacheAuthData_t *data;
1073
1074 if (!entry) {
1075 busy = 0;
1076 } else if (busy) {
1077 MSG_WARN("Cache_auth_entry: caught busy!\n");
1078 } else if (entry->Auth) {
1079 busy = 1;
1080 data = dNew(CacheAuthData_t, 1);
1081 data->auth = entry->Auth;
1082 data->url = a_Url_dup(entry->Url);
1083 data->bw = bw;
1084 entry->Auth = NULL;
1086 }
1087}
1088
1094{
1095 if (!dStrAsciiCasecmp(URL_SCHEME(url), "http") ||
1096 !dStrAsciiCasecmp(URL_SCHEME(url), "https") ||
1097 !dStrAsciiCasecmp(URL_SCHEME(url), "ftp"))
1098 return 1;
1099 return 0;
1100}
1101
1107static void Cache_null_client(int Op, CacheClient_t *Client)
1108{
1109 DilloWeb *Web = Client->Web;
1110
1111 /* make the stop button insensitive when done */
1112 if (Op == CA_Close) {
1113 if (Web->flags & WEB_RootUrl) {
1114 /* Remove this client from our active list */
1115 a_Bw_close_client(Web->bw, Client->Key);
1116 }
1117 }
1118
1119 /* else ignore */
1120
1121 return;
1122}
1123
1124typedef struct {
1125 BrowserWindow *bw;
1126 DilloUrl *url;
1127} Cache_savelink_t;
1128
1133static void Cache_savelink_cb(void *vdata)
1134{
1135 Cache_savelink_t *data = (Cache_savelink_t*) vdata;
1136
1137 a_UIcmd_save_link(data->bw, data->url);
1138 a_Url_free(data->url);
1139 dFree(data);
1140}
1141
1145static void Cache_provide_redirection_blocked_page(CacheEntry_t *entry,
1146 CacheClient_t *client)
1147{
1148 DilloWeb *clientWeb = client->Web;
1149
1150 a_Web_dispatch_by_type("text/html", clientWeb, &client->Callback,
1151 &client->CbData);
1152 client->Buf = dStrconcat("<!doctype html><html><body>"
1153 "Dillo blocked a redirection from <a href=\"",
1154 URL_STR(entry->Url), "\">", URL_STR(entry->Url),
1155 "</a> to <a href=\"", URL_STR(entry->Location), "\">",
1156 URL_STR(entry->Location), "</a> based on your domainrc "
1157 "settings.</body></html>", NULL);
1158 client->BufSize = strlen(client->Buf);
1159 (client->Callback)(CA_Send, client);
1160 dFree(client->Buf);
1161}
1162
1175static CacheEntry_t *Cache_process_queue(CacheEntry_t *entry)
1176{
1177 uint_t i;
1178 int st;
1179 const char *Type;
1180 Dstr *data;
1181 CacheClient_t *Client;
1182 DilloWeb *ClientWeb;
1183 BrowserWindow *Client_bw = NULL;
1184 static bool_t Busy = FALSE;
1185 bool_t AbortEntry = FALSE;
1186 bool_t OfferDownload = FALSE;
1187 bool_t TypeMismatch = FALSE;
1188
1189 if (Busy)
1190 MSG_ERR("FATAL!: >>>> Cache_process_queue Caught busy!!! <<<<\n");
1191 if (!(entry->Flags & CA_GotHeader))
1192 return entry;
1193 if (!(entry->Flags & CA_GotContentType)) {
1195 entry->Data->str, entry->Data->len, &Type);
1196 _MSG("Cache: detected Content-Type '%s'\n", Type);
1197 if (st == 0 || !(entry->Flags & CA_InProgress)) {
1198 if (a_Misc_content_type_check(entry->TypeHdr, Type) < 0) {
1199 MSG_HTTP("Content-Type '%s' doesn't match the real data.\n",
1200 entry->TypeHdr);
1201 TypeMismatch = TRUE;
1202 }
1203 entry->TypeDet = dStrdup(Type);
1204 entry->Flags |= CA_GotContentType;
1205 } else
1206 return entry; /* i.e., wait for more data */
1207 }
1208
1209 Busy = TRUE;
1210 for (i = 0; (Client = dList_nth_data(ClientQueue, i)); ++i) {
1211 if (Client->Url == entry->Url) {
1212 ClientWeb = Client->Web; /* It was a (void*) */
1213 Client_bw = ClientWeb->bw; /* 'bw' in a local var */
1214
1215 if (ClientWeb->flags & WEB_RootUrl) {
1216 if (!(entry->Flags & CA_MsgErased)) {
1217 /* clear the "expecting for reply..." message */
1218 a_UIcmd_set_msg(Client_bw, "");
1219 entry->Flags |= CA_MsgErased;
1220 }
1221 if (TypeMismatch) {
1222 a_UIcmd_set_msg(Client_bw,"HTTP warning: Content-Type '%s' "
1223 "doesn't match the real data.", entry->TypeHdr);
1224 OfferDownload = TRUE;
1225 }
1226 if (entry->Flags & CA_Redirect) {
1227 if (!Client->Callback) {
1228 Client->Callback = Cache_null_client;
1229 Client_bw->redirect_level++;
1230 }
1231 } else {
1232 Client_bw->redirect_level = 0;
1233 }
1234 if (entry->Flags & CA_HugeFile) {
1235 a_UIcmd_set_msg(Client_bw, "Huge file! (%d MB)",
1236 entry->ExpectedSize / (1024*1024));
1237 AbortEntry = OfferDownload = TRUE;
1238 }
1239 } else {
1240 /* For non root URLs, ignore redirections and 404 answers */
1241 if (entry->Flags & CA_Redirect || entry->Flags & CA_NotFound)
1242 Client->Callback = Cache_null_client;
1243 }
1244
1245 /* Set the client function */
1246 if (!Client->Callback) {
1247 Client->Callback = Cache_null_client;
1248
1249 if (entry->Location && !(entry->Flags & CA_Redirect)) {
1250 /* Not following redirection, so don't display page body. */
1251 } else {
1252 if (TypeMismatch) {
1253 AbortEntry = TRUE;
1254 } else {
1255 const char *curr_type = Cache_current_content_type(entry);
1256 st = a_Web_dispatch_by_type(curr_type, ClientWeb,
1257 &Client->Callback,
1258 &Client->CbData);
1259 if (st == -1) {
1260 /* MIME type is not viewable */
1261 if (ClientWeb->flags & WEB_RootUrl) {
1262 MSG("Content-Type '%s' not viewable.\n", curr_type);
1263 /* prepare a download offer... */
1264 AbortEntry = OfferDownload = TRUE;
1265 } else {
1266 /* TODO: Resource Type not handled.
1267 * Not aborted to avoid multiple connections on the
1268 * same resource. A better idea is to abort the
1269 * connection and to keep a failed-resource flag in
1270 * the cache entry. */
1271 }
1272 }
1273 }
1274 if (AbortEntry) {
1275 if (ClientWeb->flags & WEB_RootUrl)
1276 a_Nav_cancel_expect_if_eq(Client_bw, Client->Url);
1277 a_Bw_remove_client(Client_bw, Client->Key);
1278 Cache_client_dequeue(Client);
1279 --i; /* Keep the index value in the next iteration */
1280 continue;
1281 }
1282 }
1283 }
1284
1285 /* Send data to our client */
1286 if (ClientWeb->flags & WEB_Download) {
1287 /* for download, always provide original data, not translated */
1288 data = entry->Data;
1289 } else {
1290 data = Cache_data(entry);
1291 }
1292 if ((Client->BufSize = data->len) > 0) {
1293 Client->Buf = data->str;
1294 (Client->Callback)(CA_Send, Client);
1295 if (ClientWeb->flags & WEB_RootUrl) {
1296 /* show size of page received */
1297 a_UIcmd_set_page_prog(Client_bw, entry->Data->len, 1);
1298 }
1299 }
1300
1301 /* Remove client when done */
1302 if (!(entry->Flags & CA_InProgress)) {
1303 /* Copy flags to a local var */
1304 int flags = ClientWeb->flags;
1305
1306 if (ClientWeb->flags & WEB_RootUrl && entry->Location &&
1307 !(entry->Flags & CA_Redirect)) {
1309 }
1310 /* We finished sending data, let the client know */
1311 (Client->Callback)(CA_Close, Client);
1312 if (ClientWeb->flags & WEB_RootUrl) {
1313 if (entry->Flags & CA_Aborted) {
1314 a_UIcmd_set_msg(Client_bw, "ERROR: Connection closed early, "
1315 "read not complete.");
1316 }
1317 a_UIcmd_set_page_prog(Client_bw, 0, 0);
1318 }
1319 Cache_client_dequeue(Client);
1320 --i; /* Keep the index value in the next iteration */
1321
1322 /* we assert just one redirect call */
1323 if (entry->Flags & CA_Redirect)
1324 Cache_redirect(entry, flags, Client_bw);
1325 }
1326 }
1327 } /* for */
1328
1329 if (AbortEntry) {
1330 /* Abort the entry, remove it from cache, and maybe offer download. */
1331 DilloUrl *url = a_Url_dup(entry->Url);
1333 entry = NULL;
1334 if (OfferDownload) {
1335 /* Remove entry when 'conn' is already done */
1336 Cache_entry_remove(NULL, url);
1337 if (a_Cache_download_enabled(url)) {
1338 Cache_savelink_t *data = dNew(Cache_savelink_t, 1);
1339 data->bw = Client_bw;
1340 data->url = a_Url_dup(url);
1341 a_Timeout_add(0.0, Cache_savelink_cb, data);
1342 }
1343 }
1344 a_Url_free(url);
1345 } else if (entry->Auth && !(entry->Flags & CA_InProgress)) {
1346 Cache_auth_entry(entry, Client_bw);
1347 }
1348
1349 /* Trigger cleanup when there are no cache clients */
1350 if (dList_length(ClientQueue) == 0) {
1352 }
1353
1354 Busy = FALSE;
1355 _MSG("QueueSize ====> %d\n", dList_length(ClientQueue));
1356 return entry;
1357}
1358
1363{
1364 CacheEntry_t *entry;
1365 (void) ptr; /* Unused */
1366
1367 while ((entry = (CacheEntry_t *)dList_nth_data(DelayedQueue, 0))) {
1368 Cache_ref_data(entry);
1369 if ((entry = Cache_process_queue(entry))) {
1370 Cache_unref_data(entry);
1371 dList_remove(DelayedQueue, entry);
1372 }
1373 }
1376}
1377
1381static void Cache_delayed_process_queue(CacheEntry_t *entry)
1382{
1383 /* there's no need to repeat entries in the queue */
1384 if (!dList_find(DelayedQueue, entry))
1385 dList_append(DelayedQueue, entry);
1386
1387 if (DelayedQueueIdleId == 0) {
1388 _MSG(" Setting timeout callback\n");
1391 }
1392}
1393
1400{
1401 int i, n = 0;
1402 CacheClient_t *Client, *iClient;
1403
1404 if ((Client = dList_find_custom(ClientQueue, INT2VOIDP(Key),
1406 for (i = 0; (iClient = dList_nth_data(ClientQueue, i)); ++i) {
1407 if (iClient->Url == Client->Url) {
1408 ++n;
1409 }
1410 }
1411 }
1412 return (n == 1) ? Client : NULL;
1413}
1414
1420{
1421 CacheClient_t *Client;
1422 CacheEntry_t *entry;
1423 DICacheEntry *DicEntry;
1424
1425 /* The client can be in both queues at the same time */
1426 if ((Client = dList_find_custom(ClientQueue, INT2VOIDP(Key),
1428 /* Dicache */
1429 if ((DicEntry = a_Dicache_get_entry(Client->Url, Client->Version)))
1430 a_Dicache_unref(Client->Url, Client->Version);
1431
1432 /* DelayedQueue */
1433 if ((entry = Cache_entry_search(Client->Url)))
1434 dList_remove(DelayedQueue, entry);
1435
1436 /* Main queue */
1437 Cache_client_dequeue(Client);
1438
1439 } else {
1440 _MSG("WARNING: Cache_stop_client, nonexistent client\n");
1441 }
1442}
1443
1444
1449{
1450 CacheClient_t *Client;
1451 void *data;
1452
1453 /* free the client queue */
1454 while ((Client = dList_nth_data(ClientQueue, 0)))
1455 Cache_client_dequeue(Client);
1456
1457 /* Remove every cache entry */
1458 while ((data = dList_nth_data(CachedURLs, 0))) {
1460 Cache_entry_free(data);
1461 }
1462 /* Remove the cache list */
1464}
#define IORead
Definition IO.h:11
#define IOAbort
Definition IO.h:14
#define IOClose
Definition IO.h:13
const char *const AboutSplash
HTML text for startup screen.
Definition about.c:18
int a_Auth_do_auth(Dlist *challenges, const DilloUrl *url)
Given authentication challenge(s), prepare authorization.
Definition auth.c:671
#define _MSG(...)
Definition bookmarks.c:45
static char * Header
Definition bookmarks.c:86
#define MSG(...)
Definition bookmarks.c:46
int a_Bw_remove_client(BrowserWindow *bw, int ClientKey)
Remove the cache-client from the bw's list (client can be a image or a html page) Return: 0 if found,...
Definition bw.c:149
void a_Bw_close_client(BrowserWindow *bw, int ClientKey)
Close a cache-client upon successful retrieval.
Definition bw.c:167
int a_Cache_get_buf(const DilloUrl *Url, char **PBuf, int *BufSize)
Get the pointer to the URL document, and its size, from the cache entry.
Definition cache.c:552
CacheClient_t * a_Cache_client_get_if_unique(int Key)
Last Client for this entry?
Definition cache.c:1399
static void Cache_savelink_cb(void *vdata)
Save link from behind a timeout so that Cache_process_queue() can get on with its work.
Definition cache.c:1133
static void Cache_entry_remove(CacheEntry_t *entry, DilloUrl *url)
Remove an entry, from the cache.
Definition cache.c:325
static void Cache_delayed_process_queue(CacheEntry_t *entry)
Set a call to Cache_process_queue from the main cycle.
Definition cache.c:1381
static void Cache_finish_msg(CacheEntry_t *entry)
Definition cache.c:855
static Dlist * ClientQueue
A list for cache clients.
Definition cache.c:78
uint_t a_Cache_get_flags_with_redirection(const DilloUrl *url)
Get cache entry status (following redirections).
Definition cache.c:415
static void Cache_parse_header(CacheEntry_t *entry)
Scan, allocate, and set things according to header info.
Definition cache.c:660
static int Cache_entry_by_url_cmp(const void *v1, const void *v2)
Determine if two cache entries are equal, using a URL as key.
Definition cache.c:107
static void Cache_auth_entry(CacheEntry_t *entry, BrowserWindow *bw)
Set a timeout function to ask for user/password.
Definition cache.c:1069
static CacheEntry_t * Cache_entry_search_with_redirect(const DilloUrl *Url)
Given a URL, find its cache entry, following redirections.
Definition cache.c:226
static Dlist * DelayedQueue
A list for delayed clients (it holds weak pointers to cache entries, which are used to make deferred ...
Definition cache.c:82
static uint_t DelayedQueueIdleId
Definition cache.c:83
static Dlist * CachedURLs
A sorted list for cached data.
Definition cache.c:74
static int Cache_get_header(CacheEntry_t *entry, const char *buf, size_t buf_size)
Consume bytes until the whole header is got (up to a "\r\n\r\n" sequence) (Also unfold multi-line fie...
Definition cache.c:824
static void Cache_entry_init(CacheEntry_t *NewEntry, const DilloUrl *Url)
Set safe values for a new cache entry.
Definition cache.c:193
static const char * Cache_current_content_type(CacheEntry_t *entry)
Get current content type.
Definition cache.c:463
const char * a_Cache_set_content_type(const DilloUrl *url, const char *ctype, const char *from)
Change Content-Type for cache entry found by url.
Definition cache.c:492
static void Cache_client_dequeue(CacheClient_t *Client)
Remove a client from the queue.
Definition cache.c:178
static void Cache_auth_free(Dlist *auth)
Free Authentication fields.
Definition cache.c:287
void a_Cache_unref_buf(const DilloUrl *Url)
Unreference the data buffer when no longer using it.
Definition cache.c:571
static void Cache_null_client(int Op, CacheClient_t *Client)
Don't process data any further, but let the cache fill the entry.
Definition cache.c:1107
static char * Cache_parse_field(const char *header, const char *fieldname)
Extract a single field from the header, allocating and storing the value in 'field'.
Definition cache.c:583
static void Cache_auth_callback(void *vdata)
Ask for user/password and reload the page.
Definition cache.c:1054
const char * a_Cache_get_content_type(const DilloUrl *url)
Get current Content-Type for cache entry found by URL.
Definition cache.c:472
static void Cache_ref_data(CacheEntry_t *entry)
Reference the cache data.
Definition cache.c:424
static CacheEntry_t * Cache_process_queue(CacheEntry_t *entry)
Update cache clients for a single cache-entry Tasks:
Definition cache.c:1175
static void Cache_provide_redirection_blocked_page(CacheEntry_t *entry, CacheClient_t *client)
Let the client know that we're not following a redirection.
Definition cache.c:1145
void a_Cache_entry_remove_by_url(DilloUrl *url)
Wrapper for capi.
Definition cache.c:357
static void Cache_entry_inject(const DilloUrl *Url, Dstr *data_ds)
Inject full page content directly into the cache.
Definition cache.c:269
static CacheEntry_t * Cache_entry_search(const DilloUrl *Url)
Get the data structure for a cached URL (using 'Url' as the search key) If 'Url' isn't cached,...
Definition cache.c:218
static Dstr * Cache_data(CacheEntry_t *entry)
Get pointer to entry's data.
Definition cache.c:482
static int Cache_client_enqueue(const DilloUrl *Url, DilloWeb *Web, CA_Callback_t Callback, void *CbData)
Add a client to ClientQueue.
Definition cache.c:141
bool_t a_Cache_process_dbuf(int Op, const char *buf, size_t buf_size, const DilloUrl *Url)
Receive new data, update the reception buffer (for next read), update the cache, and service the clie...
Definition cache.c:897
int a_Cache_download_enabled(const DilloUrl *url)
Check whether a URL scheme is downloadable.
Definition cache.c:1093
static void Cache_entry_free(CacheEntry_t *entry)
Free the components of a CacheEntry_t struct.
Definition cache.c:299
static void Cache_unref_data(CacheEntry_t *entry)
Unreference the cache data.
Definition cache.c:442
#define HUGE_FILESIZE
Maximum filesize for a URL, before offering a download.
Definition cache.c:43
static int Cache_entry_cmp(const void *v1, const void *v2)
Determine if two cache entries are equal (used by CachedURLs)
Definition cache.c:97
void a_Cache_init(void)
Initialize cache data.
Definition cache.c:118
static void Cache_delayed_process_queue_callback(void *ptr)
Callback function for Cache_delayed_process_queue.
Definition cache.c:1362
static CacheEntry_t * Cache_entry_add(const DilloUrl *Url)
Allocate and set a new entry in the cache list.
Definition cache.c:250
#define MAX_INIT_BUF
Maximum initial size for the automatically-growing data buffer.
Definition cache.c:41
static int Cache_client_by_key_cmp(const void *client, const void *key)
Compare function for searching a Client by its key.
Definition cache.c:170
static int Cache_redirect(CacheEntry_t *entry, int Flags, BrowserWindow *bw)
Process redirections (HTTP 30x answers) (This is a work in progress –not finished yet)
Definition cache.c:996
int a_Cache_open_url(void *web, CA_Callback_t Call, void *CbData)
Try finding the url in the cache.
Definition cache.c:376
static Dlist * Cache_parse_multiple_fields(const char *header, const char *fieldname)
Extract multiple fields from the header.
Definition cache.c:617
void a_Cache_freeall(void)
Memory deallocator (only called at exit time)
Definition cache.c:1448
uint_t a_Cache_get_flags(const DilloUrl *url)
Get cache entry status.
Definition cache.c:406
void a_Cache_stop_client(int Key)
Remove a client from the client queue TODO: notify the dicache and upper layers.
Definition cache.c:1419
#define CA_Send
Definition cache.h:15
#define CA_KeepAlive
Definition cache.h:36
#define CA_NotFound
Definition cache.h:29
#define CA_InternalUrl
Definition cache.h:33
void(* CA_Callback_t)(int Op, CacheClient_t *Client)
Callback type for cache clients.
Definition cache.h:43
#define CA_Redirect
Definition cache.h:26
#define CA_ForceRedirect
Definition cache.h:27
#define CA_RedirectLoop
Definition cache.h:32
#define CA_IsEmpty
Definition cache.h:35
#define CA_GotContentType
Definition cache.h:23
#define CA_Aborted
Definition cache.h:30
#define CA_Close
Definition cache.h:16
#define CA_HugeFile
Definition cache.h:34
#define CA_MsgErased
Definition cache.h:31
#define CA_TempRedirect
Definition cache.h:28
#define CA_InProgress
Definition cache.h:25
#define CA_GotHeader
Definition cache.h:22
#define CA_GotLength
Definition cache.h:24
void a_Capi_conn_abort_by_url(const DilloUrl *url)
Abort the connection for a given url, using its CCC.
Definition capi.c:199
unsigned int uint_t
Definition d_size.h:20
unsigned char bool_t
Definition d_size.h:21
Decode * a_Decode_charset_init(const char *format)
Initialize decoder to translate from any character set known to iconv() to UTF-8.
Definition decode.c:365
Dstr * a_Decode_transfer_process(DecodeTransfer *dc, const char *instr, int inlen)
Decode 'Transfer-Encoding: chunked' data.
Definition decode.c:26
void a_Decode_transfer_free(DecodeTransfer *dc)
Definition decode.c:90
Decode * a_Decode_content_init(const char *format)
Initialize content decoder.
Definition decode.c:327
DecodeTransfer * a_Decode_transfer_init(const char *format)
Initialize transfer decoder.
Definition decode.c:291
Dstr * a_Decode_process(Decode *dc, const char *instr, int inlen)
Decode data.
Definition decode.c:392
void a_Decode_free(Decode *dc)
Definition decode.c:400
bool_t a_Decode_transfer_finished(DecodeTransfer *dc)
Definition decode.c:85
DICacheEntry * a_Dicache_get_entry(const DilloUrl *Url, int version)
Search a particular version of a URL in the Dicache.
Definition dicache.c:130
void a_Dicache_cleanup(void)
Free the imgbuf (RGB data) of unused entries.
Definition dicache.c:522
void a_Dicache_invalidate_entry(const DilloUrl *Url)
Invalidate this entry.
Definition dicache.c:212
void a_Dicache_unref(const DilloUrl *Url, int version)
Unrefs the counter of a dicache entry (it counts cache clients).
Definition dicache.c:180
char * dStrconcat(const char *s1,...)
Concatenate a NULL-terminated list of strings.
Definition dlib.c:102
void dList_insert_sorted(Dlist *lp, void *data, dCompareFunc func)
Insert an element into a sorted list.
Definition dlib.c:769
void dFree(void *mem)
Definition dlib.c:68
int dStrAsciiCasecmp(const char *s1, const char *s2)
Definition dlib.c:203
char * dStrdup(const char *s)
Definition dlib.c:77
Dlist * dList_new(int size)
Create a new empty list.
Definition dlib.c:548
Dstr * dStr_sized_new(int sz)
Create a new string with a given size.
Definition dlib.c:254
int dStrnAsciiCasecmp(const char *s1, const char *s2, size_t n)
Definition dlib.c:215
void dStr_erase(Dstr *ds, int pos_0, int len)
Erase a substring.
Definition dlib.c:388
int dList_length(Dlist *lp)
For completing the ADT.
Definition dlib.c:613
void * dList_nth_data(Dlist *lp, int n0)
Return the nth data item, NULL when not found or 'n0' is out of range.
Definition dlib.c:662
void dList_remove_fast(Dlist *lp, const void *data)
Remove a data item without preserving order.
Definition dlib.c:623
void dStr_free(Dstr *ds, int all)
Free a dillo string.
Definition dlib.c:337
void dStr_append_l(Dstr *ds, const char *s, int l)
Append a C string to a Dstr (providing length).
Definition dlib.c:308
void dStr_append_c(Dstr *ds, int c)
Append one character.
Definition dlib.c:349
char * dStrndup(const char *s, size_t sz)
Definition dlib.c:88
Dstr * dStr_new(const char *s)
Create a new string.
Definition dlib.c:325
void dList_append(Dlist *lp, void *data)
Append a data item to the list.
Definition dlib.c:597
void * dList_find_sorted(Dlist *lp, const void *data, dCompareFunc func)
Search a sorted list.
Definition dlib.c:796
void dList_free(Dlist *lp)
Free a list (not its elements)
Definition dlib.c:564
void * dList_find_custom(Dlist *lp, const void *data, dCompareFunc func)
Search a data item using a custom function.
Definition dlib.c:704
void dStr_fit(Dstr *ds)
Return memory if there's too much allocated.
Definition dlib.c:269
void dStr_truncate(Dstr *ds, int len)
Truncate a Dstr to be 'len' bytes long.
Definition dlib.c:368
void dList_remove(Dlist *lp, const void *data)
Definition dlib.c:641
void * dList_find(Dlist *lp, const void *data)
Return the found data item, or NULL if not present.
Definition dlib.c:672
#define MIN(a, b)
Definition dlib.h:30
#define dReturn_val_if_fail(expr, val)
Definition dlib.h:76
#define D_ASCII_TOLOWER(c)
Definition dlib.h:37
#define VOIDP2INT(p)
Definition dlib.h:43
#define TRUE
Definition dlib.h:23
#define FALSE
Definition dlib.h:19
#define INT2VOIDP(i)
Definition dlib.h:44
#define MAX(a, b)
Definition dlib.h:27
#define dNew(type, count)
Definition dlib.h:49
bool_t a_Domain_permit(const DilloUrl *source, const DilloUrl *dest)
Is the resource at 'source' permitted to request the resource at 'dest'?
Definition domain.c:116
#define MSG_ERR(...)
Definition dpid_common.h:23
void a_Hsts_set(const char *header, const DilloUrl *url)
The reponse for this url had an HSTS header, so let's take action.
Definition hsts.c:201
#define _MSG_WARN(...)
Definition msg.h:15
#define MSG_WARN(...)
Definition msg.h:26
int a_Misc_content_type_check(const char *EntryType, const char *DetectedType)
Check the server-supplied 'Content-Type' against our detected type.
Definition misc.c:321
int a_Misc_content_type_cmp(const char *ct1, const char *ct2)
Compare two Content-Type strings.
Definition misc.c:274
int a_Misc_get_content_type_from_data(void *Data, size_t Size, const char **PT)
Detects 'Content-Type' from a data stream sample.
Definition misc.c:136
void a_Misc_parse_content_type(const char *type, char **major, char **minor, char **charset)
Parse Content-Type string, e.g., "text/html; charset=utf-8".
Definition misc.c:210
void a_Nav_cancel_expect_if_eq(BrowserWindow *bw, const DilloUrl *url)
Definition nav.c:260
void a_Nav_reload(BrowserWindow *bw)
Definition nav.c:516
void a_Nav_push(BrowserWindow *bw, const DilloUrl *url, const DilloUrl *requester)
Definition nav.c:342
DilloPrefs prefs
Global Data.
Definition prefs.c:33
void a_Cookies_set(Dlist *cookie_strings, const DilloUrl *set_url, const char *date)
Set the value corresponding to the cookie string.
Definition cookies.c:142
#define MSG_HTTP(...)
Definition msg.h:25
Contains the specific data for a single window.
Definition bw.h:27
int redirect_level
Counter for the number of hops on a redirection.
Definition bw.h:63
Data structure for cache clients.
Definition cache.h:48
CA_Callback_t Callback
Client function.
Definition cache.h:54
const DilloUrl * Url
Pointer to a cache entry Url.
Definition cache.h:50
int Key
Primary Key for this client.
Definition cache.h:49
int Version
Dicache version of this Url (0 if not used)
Definition cache.h:51
void * CbData
Client function data.
Definition cache.h:55
uint_t BufSize
Valid size of cache-data.
Definition cache.h:53
void * Buf
Pointer to cache-data.
Definition cache.h:52
void * Web
Pointer to the Web structure of our client.
Definition cache.h:56
bool_t http_strict_transport_security
Definition prefs.h:101
Definition url.h:88
Definition dlib.h:131
Definition dlib.h:102
Dstr_char_t * str
Definition dlib.h:105
int len
Definition dlib.h:104
int flags
Additional info.
Definition web.hh:29
DilloUrl * url
Requested URL.
Definition web.hh:25
DilloUrl * requester
URL that caused this request, or < NULL if user-initiated.
Definition web.hh:26
BrowserWindow * bw
The requesting browser window [reference].
Definition web.hh:28
void a_Timeout_add(float t, TimeoutCb_t cb, void *cbdata)
Hook a one-time timeout function 'cb' after 't' seconds with 'cbdata" as its data.
Definition timeout.cc:25
void a_Timeout_remove()
Stop running a timeout function.
Definition timeout.cc:41
void a_UIcmd_set_msg(BrowserWindow *bw, const char *format,...)
Definition uicmd.cc:1513
void a_UIcmd_save_link(BrowserWindow *bw, const DilloUrl *url)
Definition uicmd.cc:1185
void a_UIcmd_set_page_prog(BrowserWindow *bw, size_t nbytes, int cmd)
Definition uicmd.cc:1460
void a_Url_set_flags(DilloUrl *u, int flags)
Set DilloUrl flags.
Definition url.c:527
int a_Url_cmp(const DilloUrl *A, const DilloUrl *B)
Compare two Url's to check if they're the same, or which one is bigger.
Definition url.c:506
void a_Url_free(DilloUrl *url)
Free a DilloUrl.
Definition url.c:208
bool_t a_Url_same_organization(const DilloUrl *u1, const DilloUrl *u2)
Definition url.c:798
DilloUrl * a_Url_new(const char *url_str, const char *base_url)
Transform (and resolve) an URL string into the respective DilloURL.
Definition url.c:371
int a_Url_host_type(const char *host)
What type of host is this?
Definition url.c:683
DilloUrl * a_Url_dup(const DilloUrl *ori)
Duplicate a Url structure.
Definition url.c:477
#define URL_HOST_NAME
Definition url.h:24
#define URL_E2EQuery
Definition url.h:35
#define URL_SpamSafe
Definition url.h:40
#define URL_FLAGS(u)
Definition url.h:79
#define URL_STR(u)
Definition url.h:76
#define URL_STR_(u)
Definition url.h:55
#define URL_SCHEME(u)
Definition url.h:70
#define URL_Post
Definition url.h:33
#define URL_Get
Definition url.h:32
#define URL_HOST(u)
Definition url.h:75
int a_Web_dispatch_by_type(const char *Type, DilloWeb *Web, CA_Callback_t *Call, void **Data)
Given the MIME content type, and a fd to read it from, this function connects the proper MIME viewer ...
Definition web.cc:50
void a_Web_free(DilloWeb *web)
Deallocate a DilloWeb structure.
Definition web.cc:152
#define WEB_RootUrl
Definition web.hh:16
#define WEB_Download
Definition web.hh:19