📄 cache.c
字号:
entry = Cache_entry_add(Url); ClientKey = Cache_client_enqueue(entry->Url, Web, Call, CbData); a_Cache_ccc(OpStart, 1, BCK, entry->CCCQuery, NULL, (void *)entry->Url); cccFunct = a_Url_get_ccc_funct(entry->Url); if ( cccFunct ) { link = a_Chain_link_new(entry->CCCQuery, a_Cache_ccc, BCK, cccFunct, 1, 1); a_Chain_bcb(OpStart, entry->CCCQuery, (void *)entry->Url, Web); } else { a_Interface_msg(Web->bw, "ERROR: unsupported protocol"); a_Cache_ccc(OpAbort, 1, FWD, entry->CCCQuery, NULL, NULL); ClientKey = 0; /* aborted */ } } return ClientKey;}/* * Try finding the url in the cache. If it hits, send the cache contents * from there. If it misses, set up a new connection. * * - 'Web' is an auxiliar data structure with misc. parameters. * - 'Call' is the callback that receives the data * - 'CbData' is custom data passed to 'Call' * Note: 'Call' and/or 'CbData' can be NULL, in that case they get set * later by a_Web_dispatch_by_type, based on content/type and 'Web' data. * * Return value: A primary key for identifying the client. */gint a_Cache_open_url(void *web, CA_Callback_t Call, void *CbData){ gint ClientKey; DICacheEntry *DicEntry; CacheData_t *entry; DilloWeb *Web = web; DilloUrl *Url = Web->url; if (URL_FLAGS(Url) & URL_E2EReload) { /* Reload operation */ Cache_prepare_reload(Url); } if ( Call ) { /* This is a verbatim request */ ClientKey = Cache_open_url(Web, Call, CbData); } else if ( (DicEntry = a_Dicache_get_entry(Url)) && (entry = Cache_entry_search(Url)) ) { /* We have it in the Dicache! */ ClientKey = Cache_client_enqueue(entry->Url, Web, Call, CbData); Cache_delayed_process_queue(entry); } else { /* It can be anything; let's request it and decide what to do when we get more info... */ ClientKey = Cache_open_url(Web, Call, CbData); } if (g_slist_find_custom(ClientQueue, GINT_TO_POINTER(ClientKey), Cache_client_key_cmp)) return ClientKey; else return 0; /* Aborted */}/* * Get the pointer to the URL document, and its size, from the cache entry. * Return: 1 cached, 0 not cached. */gint a_Cache_get_buf(const DilloUrl *Url, gchar **PBuf, gint *BufSize){ CacheData_t **stack = NULL; gint stackSize = 0; gint stackMax = 32; CacheData_t *entry; gint i; do { entry = Cache_entry_search(Url); if (entry && entry->Flags & CA_Redirect && entry->Location) { a_List_add (stack, stackSize, stackMax); stack[stackSize++] = entry; Url = entry->Location; } else break; /* Test for a redirection loop */ for (i = 0; i < stackSize - 1; i++) { if (stack[i] == entry) { g_warning ("Redirect loop for URL: >%s<\n", URL_STR_(Url)); for (i = 0; i < stackSize; i++) stack[i]->Flags |= CA_RedirectLoop; entry = NULL; } } } while (entry); g_free (stack); *BufSize = (entry) ? entry->ValidSize : 0; *PBuf = (entry) ? (gchar *) entry->Data : NULL; return (entry ? 1 : 0);}/* * Extract a single field from the header, allocating and storing the value * in 'field'. ('fieldname' must not include the trailing ':') * Return a new string with the field-content if found (NULL on error) * (This function expects a '\r' stripped header) */static char *Cache_parse_field(const char *header, const char *fieldname){ char *field; gint i, j; for ( i = 0; header[i]; i++ ) { /* Search fieldname */ for (j = 0; fieldname[j]; j++) if ( tolower(fieldname[j]) != tolower(header[i + j])) break; if ( fieldname[j] ) { /* skip to next line */ for ( i += j; header[i] != '\n'; i++); continue; } i += j; while (header[i] == ' ') i++; if (header[i] == ':' ) { /* Field found! */ while (header[++i] == ' '); for (j = 0; header[i + j] != '\n'; j++); field = g_strndup(header + i, j); return field; } } return NULL;}/* * Extract multiple fields from the header. */static GList *Cache_parse_multiple_fields(const char *header, const char *fieldname){ gint i, j; GList *fields = NULL; char *field; for (i = 0; header[i]; i++) { /* Search fieldname */ for (j = 0; fieldname[j]; j++) if (tolower(fieldname[j]) != tolower(header[i + j])) break; if (fieldname[j]) { /* skip to next line */ for (i += j; header[i] != '\n'; i++); continue; } i += j; for ( ; header[i] == ' '; i++); if (header[i] == ':' ) { /* Field found! */ while (header[++i] == ' '); for (j = 0; header[i + j] != '\n'; j++); field = g_strndup(header + i, j); fields = g_list_append(fields, field); } } return fields;}/* * Scan, allocate, and set things according to header info. * (This function needs the whole header to work) */static void Cache_parse_header(CacheData_t *entry, IOData_t *io, gint HdrLen){ gchar *header = entry->Header->str; gchar *Length, *Type, *location_str;#ifndef DISABLE_COOKIES GList *Cookies;#endif if ( HdrLen < 12 ) { /* Not enough info. */ } if ( header[9] == '3' && header[10] == '0' ) { /* 30x: URL redirection */ entry->Flags |= CA_Redirect; if ( header[11] == '1' ) /* 301 Moved Permanently */ entry->Flags |= CA_ForceRedirect; location_str = Cache_parse_field(header, "Location"); entry->Location = a_Url_new(location_str, URL_STR_(entry->Url), 0, 0, 0); g_free(location_str); } else if ( strncmp(header + 9, "404", 3) == 0 ) { entry->Flags |= CA_NotFound; } entry->ValidSize = io->Status - HdrLen; if ( (Length = Cache_parse_field(header, "Content-Length")) != NULL ) { entry->Flags |= CA_GotLength; entry->TotalSize = strtol(Length, NULL, 10); g_free(Length); if (entry->TotalSize < entry->ValidSize) entry->TotalSize = 0; }#ifndef DISABLE_COOKIES /* BUG: If a server feels like mixing Set-Cookie2 and Set-Cookie * responses which aren't identical, then we have a problem. I don't * know if that is a real issue though. */ if ( (Cookies = Cache_parse_multiple_fields(header, "Set-Cookie2")) || (Cookies = Cache_parse_multiple_fields(header, "Set-Cookie")) ) { a_Cookies_set(Cookies, entry->Url); g_list_foreach(Cookies, (GFunc)g_free, NULL); g_list_free(Cookies); }#endif /* !DISABLE_COOKIES */ if ( entry->TotalSize > 0 && entry->TotalSize >= entry->ValidSize ) { entry->Data = g_malloc(entry->TotalSize); memcpy(entry->Data, (char*)io->Buf+HdrLen, io->Status-HdrLen); /* Prepare next read */ a_IO_set_buf(io, (char *)entry->Data + entry->ValidSize, entry->TotalSize - entry->ValidSize); } else { /* We don't know the size of the transfer; A lazy server? ;) */ entry->Data = g_malloc(entry->ValidSize + entry->BuffSize); memcpy(entry->Data, (char *)io->Buf+HdrLen, entry->ValidSize); /* Prepare next read */ a_IO_set_buf(io, (char *)entry->Data + entry->ValidSize, entry->BuffSize); } /* Get Content-Type */ if ( (Type = Cache_parse_field(header, "Content-Type")) == NULL ) { MSG_HTTP("Server didn't send Content-Type in header.\n"); Type = g_strdup(a_Misc_get_content_type_from_data( entry->Data, entry->ValidSize)); } entry->Type = Type;}/* * Consume bytes until the whole header is got (up to a "\r\n\r\n" sequence) * (Also strip '\r' chars from header) */static gint Cache_get_header(IOData_t *io, CacheData_t *entry){ gint N, i; GString *hdr = entry->Header; guchar *data = io->Buf; /* Header finishes when N = 2 */ N = (hdr->len && hdr->str[hdr->len - 1] == '\n'); for ( i = 0; i < io->Status && N < 2; ++i ) { if ( data[i] == '\r' || !data[i] ) continue; N = (data[i] == '\n') ? N + 1 : 0; g_string_append_c(hdr, data[i]); } if ( N == 2 ){ /* Got whole header */ DEBUG_MSG(2, "Header [io_len=%d]\n%s", i, hdr->str); entry->Flags |= CA_GotHeader; /* Return number of original-header bytes in this io [1 based] */ return i; } return 0;}/* * Receive new data, update the reception buffer (for next read), update the * cache, and service the client queue. * * This function gets called whenever the IO has new data. * 'Op' is the operation to perform * 'VPtr' is a (void) pointer to the IO control structure */static void Cache_process_io(int Op, void *VPtr){ gint Status, len; IOData_t *io = VPtr; const DilloUrl *Url = io->ExtData; CacheData_t *entry = Cache_entry_search(Url); /* Assert a valid entry (not aborted) */ if ( !entry ) return; /* Keep track of this entry's io */ entry->io = io; if ( Op == IOClose ) { if (entry->Flags & CA_GotLength && entry->TotalSize != entry->ValidSize){ MSG_HTTP("Content-Length does NOT match message body,\n" " at: %s\n", URL_STR_(entry->Url)); } entry->Flags |= CA_GotData; entry->Flags &= ~CA_Stopped; /* it may catch up! */ entry->TotalSize = entry->ValidSize; entry->io = NULL; entry->CCCAnswer = NULL; Cache_process_queue(entry); return; } else if ( Op == IOAbort ) { /* todo: implement Abort * (eliminate cache entry and anything related) */ DEBUG_MSG(5, "Cache_process_io Op = IOAbort; not implemented yet\n"); entry->io = NULL; entry->CCCAnswer = NULL; return; } if ( !(entry->Flags & CA_GotHeader) ) { /* Haven't got the whole header yet */ len = Cache_get_header(io, entry); if ( entry->Flags & CA_GotHeader ) { /* Let's scan, allocate, and set things according to header info */ Cache_parse_header(entry, io, len); /* Now that we have it parsed, let's update our clients */ Cache_process_queue(entry); } return; } Status = io->Status; entry->ValidSize += Status; if ( Status < (gint)io->BufSize ) { /* An incomplete buffer; update buffer & size */ a_IO_set_buf(io, (char *)io->Buf + Status, io->BufSize - Status); } else if ( Status == (gint)io->BufSize ) { /* A full buffer! */ if ( !entry->TotalSize ) { /* We are receiving in small chunks... */ entry->Data = g_realloc(entry->Data,entry->ValidSize+entry->BuffSize); a_IO_set_buf(io, (char *)entry->Data + entry->ValidSize, entry->BuffSize); } else { /* We have a preallocated buffer! */ a_IO_set_buf(io, (char *)io->Buf + Status, io->BufSize - Status); } } Cache_process_queue(entry);}/* * Process redirections (HTTP 30x answers) * (This is a work in progress --not finished yet) */static gint Cache_redirect(CacheData_t *entry, gint Flags, BrowserWindow *bw){ DilloUrl *NewUrl; /* if there's a redirect loop, stop now */ if (entry->Flags & CA_RedirectLoop) { a_Interface_msg(bw, "ERROR: redirect loop for: %s", URL_STR_(entry->Url)); return 0; } if ( ((entry->Flags & CA_Redirect) && entry->Location) && ((entry->Flags & CA_ForceRedirect) || !entry->ValidSize || entry->ValidSize < 1024 ) ) { DEBUG_MSG(3, ">>>Redirect from: %s\n to %s\n", URL_STR_(entry->Url), URL_STR_(entry->Location)); DEBUG_MSG(3,"%s", entry->Header->str); if ( Flags & WEB_RootUrl ) { /* Redirection of the main page */ NewUrl = a_Url_new(URL_STR_(entry->Location), URL_STR_(entry->Url), 0, 0, 0);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -