📄 cache.c
字号:
a_Nav_push(bw, NewUrl); a_Url_free(NewUrl); } else { /* Sub entity redirection (most probably an image) */ if ( !entry->ValidSize ) { DEBUG_MSG(3,">>>Image redirection without entity-content<<<\n"); } else { DEBUG_MSG(3, ">>>Image redirection with entity-content<<<\n"); } } } return 0;}/* * Do nothing, but let the cache fill the entry. * (Currently used to ignore image redirects --Jcid) */void a_Cache_null_client(int Op, CacheClient_t *Client){ return;}/* * Update cache clients for a single cache-entry * Tasks: * - Set the client function (if not already set) * - Look if new data is available and pass it to client functions * - Remove clients when done * - Call redirect handler * * todo: Implement CA_Abort Op in client callback */static void Cache_process_queue(CacheData_t *entry){ gint i, st; CacheClient_t *Client; DilloWeb *ClientWeb; BrowserWindow *Client_bw = NULL; static gboolean Busy = FALSE; gboolean AbortEntry = FALSE; if ( Busy ) DEBUG_MSG(5, "FATAL!:*** >>>> Cache_process_queue Caught busy!!!\n"); Busy = TRUE; if ( !(entry->Flags & CA_GotHeader) ) { Busy = FALSE; return; } for ( i = 0; (Client = g_slist_nth_data(ClientQueue, i)); ++i ) { if ( Client->Url == entry->Url ) { ClientWeb = Client->Web; /* It was a (void*) */ Client_bw = ClientWeb->bw; /* 'bw' in a local var */ if (ClientWeb->flags & WEB_RootUrl) { if (!(entry->Flags & CA_MsgErased)) { /* clear the "expecting for reply..." message */ a_Interface_msg(Client_bw, ""); entry->Flags |= CA_MsgErased; } if (entry->Flags & CA_Redirect) Client->Callback = a_Cache_null_client; } else { /* For non root URLs, ignore redirections and 404 answers */ if (entry->Flags & CA_Redirect || entry->Flags & CA_NotFound) Client->Callback = a_Cache_null_client; } /* Set the client function */ if (!Client->Callback) { st = a_Web_dispatch_by_type(entry->Type, ClientWeb, &Client->Callback, &Client->CbData); if (st == -1) { /* MIME type is not viewable */ Client->Callback = a_Cache_null_client; Client->CbData = NULL; if (ClientWeb->flags & WEB_RootUrl) { /* Unhandled MIME type, prepare a download offer... */ AbortEntry = TRUE; a_Interface_remove_client(Client_bw, Client->Key); Cache_client_dequeue(Client, NULLKey); --i; /* Keep the index value in the next iteration */ continue; } } } /* Send data to our client */ if ( (Client->BufSize = entry->ValidSize) > 0) { Client->Buf = (guchar *)entry->Data; (Client->Callback)(CA_Send, Client); } /* Remove client when done */ if ( (entry->Flags & CA_GotData) ) { /* Copy flags to a local var */ gint flags = ClientWeb->flags; /* We finished sending data, let the client know */ if (!Client->Callback) DEBUG_MSG(3, "Client Callback is NULL"); else (Client->Callback)(CA_Close, Client); Cache_client_dequeue(Client, NULLKey); --i; /* Keep the index value in the next iteration */ if ( entry->Flags & CA_Redirect ) Cache_redirect(entry, flags, Client_bw); } } } /* for */ if (AbortEntry) { /* Abort the entry, remove it from cache, and offer download. * (the dialog is made before 'entry' is freed) */ a_Interface_offer_link_download(Client_bw, entry->Url); Cache_entry_remove(entry, NULL); } Busy = FALSE; DEBUG_MSG(1, "QueueSize ====> %d\n", g_slist_length(ClientQueue));}/* * Callback function for Cache_delayed_process_queue. */static gint Cache_delayed_process_queue_callback(gpointer data){ gpointer entry; while ((entry = g_slist_nth_data(DelayedQueue, 0))) { Cache_process_queue( (CacheData_t *)entry ); /* note that if Cache_process_queue removes the entry, * the following g_slist_remove has no effect. */ DelayedQueue = g_slist_remove(DelayedQueue, entry); } DelayedQueueIdleId = 0; return FALSE;}/* * Set a call to Cache_process_queue from the gtk_main cycle. */static void Cache_delayed_process_queue(CacheData_t *entry){ /* there's no need to repeat entries in the queue */ if (!g_slist_find(DelayedQueue, entry)) DelayedQueue = g_slist_prepend(DelayedQueue, entry); if (DelayedQueueIdleId == 0) DelayedQueueIdleId = gtk_idle_add((GtkFunction)Cache_delayed_process_queue_callback, NULL);}/* * Remove a cache client * todo: beware of downloads */static void Cache_remove_client_raw(CacheClient_t *Client, gint Key){ Cache_client_dequeue(Client, Key);}/* * Remove every Interface-client of a single Url. * todo: beware of downloads * (this is transitory code) */static void Cache_remove_interface_clients(const DilloUrl *Url){ gint i; DilloWeb *Web; CacheClient_t *Client; for ( i = 0; (Client = g_slist_nth_data(ClientQueue, i)); ++i ) { if ( Client->Url == Url ) { Web = Client->Web; a_Interface_remove_client(Web->bw, Client->Key); } }}/* * Remove a client from the client queue * todo: notify the dicache and upper layers */static void Cache_stop_client(gint Key, gint force){ CacheClient_t *Client; CacheData_t *entry; GSList *List; DilloUrl *url; if (!(List = g_slist_find_custom(ClientQueue, GINT_TO_POINTER(Key), Cache_client_key_cmp))){ DEBUG_MSG(5, "WARNING: Cache_stop_client, inexistent client\n"); return; } Client = List->data; url = (DilloUrl *)Client->Url; Cache_remove_client_raw(Client, NULLKey); if (force && !g_slist_find_custom(ClientQueue, url, Cache_client_url_cmp)) { /* it was the last client of this entry */ if ((entry = Cache_entry_search(url))) { if (entry->CCCQuery) { a_Cache_ccc(OpAbort, 1, BCK, entry->CCCQuery, NULL, NULL); } else if (entry->CCCAnswer) { a_Cache_ccc(OpStop, 2, BCK, entry->CCCAnswer, NULL, Client); } } }}/* * Remove a client from the client queue * (It may keep feeding the cache, but nothing else) */void a_Cache_stop_client(gint Key){ Cache_stop_client(Key, 0);}/* * CCC function for the CACHE module */void a_Cache_ccc(int Op, int Branch, int Dir, ChainLink *Info, void *Data1, void *Data2){ CacheData_t *entry; a_Chain_debug_msg("a_Cache_ccc", Op, Branch, Dir); if ( Branch == 1 ) { if (Dir == BCK) { /* Querying branch */ switch (Op) { case OpStart: /* Localkey = entry->Url */ Info->LocalKey = Data2; break; case OpStop: break; case OpAbort: Cache_entry_remove_raw(NULL, Info->LocalKey); a_Chain_bcb(OpAbort, Info, NULL, NULL); g_free(Info); break; } } else { /* FWD */ switch (Op) { case OpSend: /* Start the answer-reading chain */ a_Cache_ccc(OpStart, 2, BCK, a_Chain_new(), Data1, Info->LocalKey); break; case OpEnd: /* unlink HTTP_Info */ a_Chain_del_link(Info, BCK); /* 'entry->CCCQuery' and 'Info' point to the same place! */ if ((entry = Cache_entry_search(Info->LocalKey)) != NULL) entry->CCCQuery = NULL; g_free(Info); break; case OpAbort: /* Unlink HTTP_Info */ a_Chain_del_link(Info, BCK); /* remove interface client-references of this entry */ Cache_remove_interface_clients(Info->LocalKey); /* remove clients of this entry */ Cache_stop_clients(Info->LocalKey, 0); /* remove the entry */ Cache_entry_remove_raw(NULL, Info->LocalKey); g_free(Info); break; } } } else if (Branch == 2) { if (Dir == FWD) { /* Answering branch */ switch (Op) { case OpStart: /* Data2 = entry->Url */ Info->LocalKey = Data2; if ((entry = Cache_entry_search(Info->LocalKey))) { entry->CCCAnswer = Info; } else { /* The cache-entry was removed */ a_Chain_bcb(OpAbort, Info, NULL, NULL); g_free(Info); } break; case OpSend: /* Send data */ if ((entry = Cache_entry_search(Info->LocalKey))) { Cache_process_io(IORead, Data1); } else { a_Chain_bcb(OpAbort, Info, NULL, NULL); g_free(Info); } break; case OpEnd: /* Unlink HTTP_Info */ a_Chain_del_link(Info, BCK); g_free(Info); Cache_process_io(IOClose, Data1); break; case OpAbort: a_Chain_del_link(Info, BCK); g_free(Info); Cache_process_io(IOAbort, Data1); break; } } else { /* BCK */ switch (Op) { case OpStart: { IOData_t *io2; Info->LocalKey = Data2; if ((entry = Cache_entry_search(Data2))) // Is Data2 valid? entry->CCCAnswer = Info; /* Link IO to receive the answer */ io2 = a_IO_new(IORead, *(int*)Data1); a_IO_set_buf(io2, NULL, IOBufLen); io2->ExtData = Data2; // We have it as LocalKey a_Chain_link_new(Info, a_Cache_ccc, BCK, a_IO_ccc, 2, 2); a_Chain_bcb(OpStart, Info, io2, NULL); break; } case OpStop: MSG(" Not implemented\n"); break; case OpAbort: Cache_entry_remove_raw(NULL, Info->LocalKey); a_Chain_bcb(OpAbort, Info, NULL, NULL); g_free(Info); break; } } }}static gbooleanCache_remove_hash_entry(gpointer key, gpointer value, gpointer user_data){ Cache_entry_free((CacheData_t *)value); return TRUE;}/* * Memory deallocator (only called at exit time) */void a_Cache_freeall(void){ CacheClient_t *Client; /* free the client queue */ while ( (Client = g_slist_nth_data(ClientQueue, 0)) ) Cache_client_dequeue(Client, NULLKey); /* free the main cache */ /* Remove every cache entry */ g_hash_table_foreach_remove(CacheHash, (GHRFunc)Cache_remove_hash_entry, NULL); /* Remove the cache hash */ g_hash_table_destroy(CacheHash);}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -