⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 cache.c

📁 浏览器的源代码,可移植到嵌入式设备.
💻 C
📖 第 1 页 / 共 3 页
字号:
      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 + -