41#define MAX_INIT_BUF 1024*1024
43#define HUGE_FILESIZE 15*1024*1024
99 const CacheEntry_t *d1 = v1, *d2 = v2;
109 const DilloUrl *u1 = ((CacheEntry_t*)v1)->Url;
144 static int ClientKey = 0;
147 if (ClientKey < INT_MAX)
153 NewClient->
Key = ClientKey;
154 NewClient->
Url = Url;
156 NewClient->
Buf = NULL;
159 NewClient->
CbData = CbData;
160 NewClient->
Web = Web;
196 NewEntry->TypeDet = NULL;
197 NewEntry->TypeHdr = NULL;
198 NewEntry->TypeMeta = NULL;
199 NewEntry->TypeNorm = NULL;
201 NewEntry->Location = NULL;
202 NewEntry->Auth = NULL;
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;
239 if (entry->Flags &
CA_Redirect && entry->Location) {
240 Url = entry->Location;
252 CacheEntry_t *old_entry, *new_entry;
255 MSG_WARN(
"Cache_entry_add, leaking an entry.\n");
259 new_entry =
dNew(CacheEntry_t, 1);
277 entry->Flags &= ~CA_IsEmpty;
281 entry->ExpectedSize = entry->TransferSize = entry->Data->len;
302 dFree(entry->TypeDet);
303 dFree(entry->TypeHdr);
304 dFree(entry->TypeMeta);
305 dFree(entry->TypeNorm);
311 if (entry->CharsetDecoder)
313 if (entry->TransferDecoder)
315 if (entry->ContentDecoder)
337 if (Client->
Url == entry->Url) {
409 return (entry ? entry->Flags : 0);
418 return (entry ? entry->Flags : 0);
427 entry->DataRefcount++;
428 _MSG(
"DataRefcount++: %d\n", entry->DataRefcount);
429 if (entry->CharsetDecoder &&
430 (!entry->UTF8Data || entry->DataRefcount == 1)) {
445 entry->DataRefcount--;
446 _MSG(
"DataRefcount--: %d\n", entry->DataRefcount);
448 if (entry->CharsetDecoder) {
449 if (entry->DataRefcount == 0) {
451 entry->UTF8Data = NULL;
452 }
else if (entry->DataRefcount < 0) {
453 MSG_ERR(
"Cache_unref_data: negative refcount\n");
454 entry->DataRefcount = 0;
465 return entry->TypeNorm ? entry->TypeNorm : entry->TypeMeta ? entry->TypeMeta
466 : entry->TypeHdr ? entry->TypeHdr : entry->TypeDet;
484 return entry->UTF8Data ? entry->UTF8Data : entry->Data;
496 char *major, *minor, *charset;
501 _MSG(
"a_Cache_set_content_type {%s} {%s}\n", ctype,
URL_STR(url));
504 if (entry->TypeMeta || (*from ==
'h' && entry->TypeHdr) ) {
510 entry->TypeHdr =
dStrdup(ctype);
513 entry->TypeMeta =
dStrdup(ctype);
518 if (*from ==
'm' && charset &&
519 ((!major || !*major) && (!minor || !*minor))) {
521 entry->TypeNorm =
dStrconcat(entry->TypeDet, ctype, NULL);
522 }
else if (*from ==
'm' &&
526 entry->TypeNorm =
dStrconcat(
"application/xhtml+xml",
527 "; charset=", charset, NULL);
529 entry->TypeNorm =
dStrdup(
"application/xhtml+xml");
533 if (entry->CharsetDecoder)
540 entry->UTF8Data = NULL;
560 *BufSize = data->
len;
565 return (entry ? 1 : 0);
588 for (i = 0; header[i]; i++) {
590 for (j = 0; fieldname[j]; j++)
595 for ( i += j; header[i] !=
'\n'; i++);
600 if (header[i] ==
':') {
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'))
609 while (header[i] !=
'\n') i++;
618 const char *fieldname)
624 for (i = 0; header[i]; i++) {
626 for (j = 0; fieldname[j]; j++)
631 for (i += j; header[i] !=
'\n'; i++);
636 if (header[i] ==
':') {
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'))
645 while (header[i] !=
'\n') i++;
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
672 _MSG(
"Cache_parse_header\n");
674 if (entry->Header->len > 12) {
675 if (header[9] ==
'1' && header[10] ==
'0' && header[11] ==
'0') {
677 MSG(
"An actual 100 Continue header!\n");
678 entry->Flags &= ~CA_GotHeader;
683 if (header[9] ==
'3' && header[10] ==
'0' &&
695 MSG(
"Redirection not followed from %s to %s\n",
699 if (header[11] ==
'1')
701 else if (header[11] ==
'2')
705 }
else if (strncmp(header + 9,
"401", 3) == 0) {
708 }
else if (strncmp(header + 9,
"404", 3) == 0) {
722 entry->Flags &= ~CA_KeepAlive;
726 entry->Flags &= ~CA_KeepAlive;
754 MSG_HTTP(
"Content-Length and non-identity Transfer-Encoding "
755 "headers both present.\n");
758 entry->ExpectedSize =
MAX(strtol(Length, NULL, 10), 0);
765#ifndef DISABLE_COOKIES
770 if (client->
Url == entry->Url) {
797 if (entry->ExpectedSize > 0) {
813 _MSG(
"TypeHdr {%s} {%s}\n", Type,
URL_STR(entry->Url));
814 _MSG(
"TypeMeta {%s}\n", entry->TypeMeta);
825 const char *buf,
size_t buf_size)
828 Dstr *hdr = entry->Header;
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])
835 if (N == 1 && (buf[i] ==
' ' || buf[i] ==
'\t')) {
837 _MSG(
"Multiple-line header!\n");
840 N = (buf[i] ==
'\n') ? N + 1 : 0;
846 _MSG(
"Header [buf_size=%d]\n%s", i, hdr->
str);
862 if ((entry->ExpectedSize || entry->TransferSize) &&
863 entry->TypeHdr == NULL) {
864 MSG_HTTP(
"Message with a body lacked Content-Type header.\n");
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));
871 entry->Flags &= ~CA_InProgress;
872 if (entry->TransferDecoder) {
874 entry->TransferDecoder = NULL;
876 if (entry->ContentDecoder) {
878 entry->ContentDecoder = NULL;
902 Dstr *dstr1, *dstr2, *dstr3;
909 _MSG(
"__a_Cache_process_dbuf__\n");
925 len = buf_size - offset;
926 entry->TransferSize += len;
927 dstr1 = dstr2 = dstr3 = NULL;
930 if (entry->TransferDecoder) {
936 if (entry->ContentDecoder) {
942 if (entry->CharsetDecoder && entry->UTF8Data) {
950 if (entry->Data->len)
951 entry->Flags &= ~CA_IsEmpty;
954 (entry->TransferSize >= entry->ExpectedSize)) {
971 if (entry->Data->len) {
972 MSG(
"Premature close for %s\n",
URL_STR(entry->Url));
979 if (Client->
Url == entry->Url) {
1004 a_UIcmd_set_msg(bw,
"WARNING: local URL with redirection. Aborting.");
1018 if ((entry->Flags &
CA_Redirect && entry->Location) &&
1020 !entry->Data->len || entry->Data->len < 1024)) {
1022 _MSG(
">>>> Redirect from: %s\n to %s <<<<\n",
1024 _MSG(
"%s", entry->Header->str);
1035 if (!entry->Data->len) {
1036 _MSG(
">>>> Image redirection without entity-content <<<<\n");
1038 _MSG(
">>>> Image redirection with entity-content <<<<\n");
1056 CacheAuthData_t *data = (CacheAuthData_t *)vdata;
1071 static int busy = 0;
1072 CacheAuthData_t *data;
1077 MSG_WARN(
"Cache_auth_entry: caught busy!\n");
1078 }
else if (entry->Auth) {
1080 data =
dNew(CacheAuthData_t, 1);
1081 data->auth = entry->Auth;
1135 Cache_savelink_t *data = (Cache_savelink_t*) vdata;
1153 "Dillo blocked a redirection from <a href=\"",
1155 "</a> to <a href=\"",
URL_STR(entry->Location),
"\">",
1156 URL_STR(entry->Location),
"</a> based on your domainrc "
1157 "settings.</body></html>", NULL);
1190 MSG_ERR(
"FATAL!: >>>> Cache_process_queue Caught busy!!! <<<<\n");
1195 entry->Data->str, entry->Data->len, &Type);
1196 _MSG(
"Cache: detected Content-Type '%s'\n", Type);
1199 MSG_HTTP(
"Content-Type '%s' doesn't match the real data.\n",
1201 TypeMismatch =
TRUE;
1203 entry->TypeDet =
dStrdup(Type);
1211 if (Client->
Url == entry->Url) {
1212 ClientWeb = Client->
Web;
1213 Client_bw = ClientWeb->
bw;
1223 "doesn't match the real data.", entry->TypeHdr);
1224 OfferDownload =
TRUE;
1236 entry->ExpectedSize / (1024*1024));
1237 AbortEntry = OfferDownload =
TRUE;
1249 if (entry->Location && !(entry->Flags &
CA_Redirect)) {
1262 MSG(
"Content-Type '%s' not viewable.\n", curr_type);
1264 AbortEntry = OfferDownload =
TRUE;
1304 int flags = ClientWeb->
flags;
1315 "read not complete.");
1334 if (OfferDownload) {
1338 Cache_savelink_t *data =
dNew(Cache_savelink_t, 1);
1339 data->bw = Client_bw;
1345 }
else if (entry->Auth && !(entry->Flags &
CA_InProgress)) {
1364 CacheEntry_t *entry;
1388 _MSG(
" Setting timeout callback\n");
1407 if (iClient->
Url == Client->
Url) {
1412 return (n == 1) ? Client : NULL;
1422 CacheEntry_t *entry;
1440 _MSG(
"WARNING: Cache_stop_client, nonexistent client\n");
const char *const AboutSplash
HTML text for startup screen.
int a_Auth_do_auth(Dlist *challenges, const DilloUrl *url)
Given authentication challenge(s), prepare authorization.
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,...
void a_Bw_close_client(BrowserWindow *bw, int ClientKey)
Close a cache-client upon successful retrieval.
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.
CacheClient_t * a_Cache_client_get_if_unique(int Key)
Last Client for this entry?
static void Cache_savelink_cb(void *vdata)
Save link from behind a timeout so that Cache_process_queue() can get on with its work.
static void Cache_entry_remove(CacheEntry_t *entry, DilloUrl *url)
Remove an entry, from the cache.
static void Cache_delayed_process_queue(CacheEntry_t *entry)
Set a call to Cache_process_queue from the main cycle.
static void Cache_finish_msg(CacheEntry_t *entry)
static Dlist * ClientQueue
A list for cache clients.
uint_t a_Cache_get_flags_with_redirection(const DilloUrl *url)
Get cache entry status (following redirections).
static void Cache_parse_header(CacheEntry_t *entry)
Scan, allocate, and set things according to header info.
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.
static void Cache_auth_entry(CacheEntry_t *entry, BrowserWindow *bw)
Set a timeout function to ask for user/password.
static CacheEntry_t * Cache_entry_search_with_redirect(const DilloUrl *Url)
Given a URL, find its cache entry, following redirections.
static Dlist * DelayedQueue
A list for delayed clients (it holds weak pointers to cache entries, which are used to make deferred ...
static uint_t DelayedQueueIdleId
static Dlist * CachedURLs
A sorted list for cached data.
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...
static void Cache_entry_init(CacheEntry_t *NewEntry, const DilloUrl *Url)
Set safe values for a new cache entry.
static const char * Cache_current_content_type(CacheEntry_t *entry)
Get current content type.
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.
static void Cache_client_dequeue(CacheClient_t *Client)
Remove a client from the queue.
static void Cache_auth_free(Dlist *auth)
Free Authentication fields.
void a_Cache_unref_buf(const DilloUrl *Url)
Unreference the data buffer when no longer using it.
static void Cache_null_client(int Op, CacheClient_t *Client)
Don't process data any further, but let the cache fill the entry.
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'.
static void Cache_auth_callback(void *vdata)
Ask for user/password and reload the page.
const char * a_Cache_get_content_type(const DilloUrl *url)
Get current Content-Type for cache entry found by URL.
static void Cache_ref_data(CacheEntry_t *entry)
Reference the cache data.
static CacheEntry_t * Cache_process_queue(CacheEntry_t *entry)
Update cache clients for a single cache-entry Tasks:
static void Cache_provide_redirection_blocked_page(CacheEntry_t *entry, CacheClient_t *client)
Let the client know that we're not following a redirection.
void a_Cache_entry_remove_by_url(DilloUrl *url)
Wrapper for capi.
static void Cache_entry_inject(const DilloUrl *Url, Dstr *data_ds)
Inject full page content directly into the cache.
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,...
static Dstr * Cache_data(CacheEntry_t *entry)
Get pointer to entry's data.
static int Cache_client_enqueue(const DilloUrl *Url, DilloWeb *Web, CA_Callback_t Callback, void *CbData)
Add a client to ClientQueue.
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...
int a_Cache_download_enabled(const DilloUrl *url)
Check whether a URL scheme is downloadable.
static void Cache_entry_free(CacheEntry_t *entry)
Free the components of a CacheEntry_t struct.
static void Cache_unref_data(CacheEntry_t *entry)
Unreference the cache data.
#define HUGE_FILESIZE
Maximum filesize for a URL, before offering a download.
static int Cache_entry_cmp(const void *v1, const void *v2)
Determine if two cache entries are equal (used by CachedURLs)
void a_Cache_init(void)
Initialize cache data.
static void Cache_delayed_process_queue_callback(void *ptr)
Callback function for Cache_delayed_process_queue.
static CacheEntry_t * Cache_entry_add(const DilloUrl *Url)
Allocate and set a new entry in the cache list.
#define MAX_INIT_BUF
Maximum initial size for the automatically-growing data buffer.
static int Cache_client_by_key_cmp(const void *client, const void *key)
Compare function for searching a Client by its key.
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)
int a_Cache_open_url(void *web, CA_Callback_t Call, void *CbData)
Try finding the url in the cache.
static Dlist * Cache_parse_multiple_fields(const char *header, const char *fieldname)
Extract multiple fields from the header.
void a_Cache_freeall(void)
Memory deallocator (only called at exit time)
uint_t a_Cache_get_flags(const DilloUrl *url)
Get cache entry status.
void a_Cache_stop_client(int Key)
Remove a client from the client queue TODO: notify the dicache and upper layers.
void(* CA_Callback_t)(int Op, CacheClient_t *Client)
Callback type for cache clients.
#define CA_GotContentType
void a_Capi_conn_abort_by_url(const DilloUrl *url)
Abort the connection for a given url, using its CCC.
Decode * a_Decode_charset_init(const char *format)
Initialize decoder to translate from any character set known to iconv() to UTF-8.
Dstr * a_Decode_transfer_process(DecodeTransfer *dc, const char *instr, int inlen)
Decode 'Transfer-Encoding: chunked' data.
void a_Decode_transfer_free(DecodeTransfer *dc)
Decode * a_Decode_content_init(const char *format)
Initialize content decoder.
DecodeTransfer * a_Decode_transfer_init(const char *format)
Initialize transfer decoder.
Dstr * a_Decode_process(Decode *dc, const char *instr, int inlen)
Decode data.
void a_Decode_free(Decode *dc)
bool_t a_Decode_transfer_finished(DecodeTransfer *dc)
DICacheEntry * a_Dicache_get_entry(const DilloUrl *Url, int version)
Search a particular version of a URL in the Dicache.
void a_Dicache_cleanup(void)
Free the imgbuf (RGB data) of unused entries.
void a_Dicache_invalidate_entry(const DilloUrl *Url)
Invalidate this entry.
void a_Dicache_unref(const DilloUrl *Url, int version)
Unrefs the counter of a dicache entry (it counts cache clients).
char * dStrconcat(const char *s1,...)
Concatenate a NULL-terminated list of strings.
void dList_insert_sorted(Dlist *lp, void *data, dCompareFunc func)
Insert an element into a sorted list.
int dStrAsciiCasecmp(const char *s1, const char *s2)
char * dStrdup(const char *s)
Dlist * dList_new(int size)
Create a new empty list.
Dstr * dStr_sized_new(int sz)
Create a new string with a given size.
int dStrnAsciiCasecmp(const char *s1, const char *s2, size_t n)
void dStr_erase(Dstr *ds, int pos_0, int len)
Erase a substring.
int dList_length(Dlist *lp)
For completing the ADT.
void * dList_nth_data(Dlist *lp, int n0)
Return the nth data item, NULL when not found or 'n0' is out of range.
void dList_remove_fast(Dlist *lp, const void *data)
Remove a data item without preserving order.
void dStr_free(Dstr *ds, int all)
Free a dillo string.
void dStr_append_l(Dstr *ds, const char *s, int l)
Append a C string to a Dstr (providing length).
void dStr_append_c(Dstr *ds, int c)
Append one character.
char * dStrndup(const char *s, size_t sz)
Dstr * dStr_new(const char *s)
Create a new string.
void dList_append(Dlist *lp, void *data)
Append a data item to the list.
void * dList_find_sorted(Dlist *lp, const void *data, dCompareFunc func)
Search a sorted list.
void dList_free(Dlist *lp)
Free a list (not its elements)
void * dList_find_custom(Dlist *lp, const void *data, dCompareFunc func)
Search a data item using a custom function.
void dStr_fit(Dstr *ds)
Return memory if there's too much allocated.
void dStr_truncate(Dstr *ds, int len)
Truncate a Dstr to be 'len' bytes long.
void dList_remove(Dlist *lp, const void *data)
void * dList_find(Dlist *lp, const void *data)
Return the found data item, or NULL if not present.
#define dReturn_val_if_fail(expr, val)
#define D_ASCII_TOLOWER(c)
#define dNew(type, count)
bool_t a_Domain_permit(const DilloUrl *source, const DilloUrl *dest)
Is the resource at 'source' permitted to request the resource at 'dest'?
void a_Hsts_set(const char *header, const DilloUrl *url)
The reponse for this url had an HSTS header, so let's take action.
int a_Misc_content_type_check(const char *EntryType, const char *DetectedType)
Check the server-supplied 'Content-Type' against our detected type.
int a_Misc_content_type_cmp(const char *ct1, const char *ct2)
Compare two Content-Type strings.
int a_Misc_get_content_type_from_data(void *Data, size_t Size, const char **PT)
Detects 'Content-Type' from a data stream sample.
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".
void a_Nav_cancel_expect_if_eq(BrowserWindow *bw, const DilloUrl *url)
void a_Nav_reload(BrowserWindow *bw)
void a_Nav_push(BrowserWindow *bw, const DilloUrl *url, const DilloUrl *requester)
DilloPrefs prefs
Global Data.
void a_Cookies_set(Dlist *cookie_strings, const DilloUrl *set_url, const char *date)
Set the value corresponding to the cookie string.
Contains the specific data for a single window.
int redirect_level
Counter for the number of hops on a redirection.
Data structure for cache clients.
CA_Callback_t Callback
Client function.
const DilloUrl * Url
Pointer to a cache entry Url.
int Key
Primary Key for this client.
int Version
Dicache version of this Url (0 if not used)
void * CbData
Client function data.
uint_t BufSize
Valid size of cache-data.
void * Buf
Pointer to cache-data.
void * Web
Pointer to the Web structure of our client.
bool_t http_strict_transport_security
int flags
Additional info.
DilloUrl * url
Requested URL.
DilloUrl * requester
URL that caused this request, or < NULL if user-initiated.
BrowserWindow * bw
The requesting browser window [reference].
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.
void a_Timeout_remove()
Stop running a timeout function.
void a_UIcmd_set_msg(BrowserWindow *bw, const char *format,...)
void a_UIcmd_save_link(BrowserWindow *bw, const DilloUrl *url)
void a_UIcmd_set_page_prog(BrowserWindow *bw, size_t nbytes, int cmd)
void a_Url_set_flags(DilloUrl *u, int flags)
Set DilloUrl flags.
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.
void a_Url_free(DilloUrl *url)
Free a DilloUrl.
bool_t a_Url_same_organization(const DilloUrl *u1, const DilloUrl *u2)
DilloUrl * a_Url_new(const char *url_str, const char *base_url)
Transform (and resolve) an URL string into the respective DilloURL.
int a_Url_host_type(const char *host)
What type of host is this?
DilloUrl * a_Url_dup(const DilloUrl *ori)
Duplicate a Url structure.
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 ...
void a_Web_free(DilloWeb *web)
Deallocate a DilloWeb structure.