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

📄 cache.c

📁 嵌入式浏览器Dillo源码
💻 C
📖 第 1 页 / 共 3 页
字号:
                                 CCC_FWD, cccFunct);         cccFunct(OpStart, 1, link, (void *)entry->Url, Web);      } else {         a_Interface_msg(Web->bw, "ERROR: unsupported protocol");         a_Cache_ccc(OpAbort, 1, entry->CCCQuery, NULL, NULL);      }   } else {      /* Feed our client with cached data */      ClientKey = Cache_client_enqueue(entry->Url, Web, Call, CbData);      Cache_delayed_process_queue(entry);   }   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 */}/* * Return the pointer to URL 'Data' in the cache. * (We also return its size in 'Size' and take care of redirections) */char *a_Cache_url_read(const DilloUrl *Url, gint *Size){   CacheData_t **stack = NULL;   gint stackSize = 0;   gint stackMax = 32;   CacheData_t *entry = NULL;   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);   *Size = (entry) ? entry->ValidSize : 0;   return (entry) ? (char *) entry->Data : NULL;}/* * 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. */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;}/* * Detects 'Content-Type' when the server does not supply one. * It uses the magic(5) logic from file(1). Currently, it * only checks the few mime types that Dillo supports. * * 'Data' is a pointer to the first bytes of the raw data. */static gchar *Cache_get_type_from_data(void *Data, size_t Size){   static gchar *Types[] = {      "application/octet-stream",      "text/html", "text/plain",      "image/gif", "image/png", "image/jpeg",   };   gint Type = 0;   gchar *p = Data;   int i;   /* HTML try */   for (i = 0; i < Size && isspace(p[i]); ++i);   if ((Size - i >= 5 && !g_strncasecmp(p+i, "<html", 5)) ||       (Size - i >= 5 && !g_strncasecmp(p+i, "<head", 5)) ||       (Size - i >= 6 && !g_strncasecmp(p+i, "<title", 6)) ||       (Size - i >= 14 && !g_strncasecmp(p+i, "<!doctype html", 14))) {      Type = 1;   /* Images */   } else if (Size >= 4 && !g_strncasecmp(p, "GIF8", 4)) {      Type = 3;   } else if (Size >= 4 && !g_strncasecmp(p, "\x89PNG", 4)) {      Type = 4;   } else if (Size >= 2 && !g_strncasecmp(p, "\xff\xd8", 2)) {      /* JPEG has the first 2 bytes set to 0xffd8 in BigEndian - looking       * at the character representation should be machine independent. */      Type = 5;   /* Text */   } else {      /* We'll assume ASCII if chars are below 128 (after all, this       * is a last resort when the server doesn't send Content-Type) */      for (i = 0; i < Size && i < 256; i++)         if ((guchar) p[i] > 127)            break;      Type = (i < 12 || (guchar) p[i] > 127) ? 0 : 2;   }   return g_strdup(Types[Type]);}/* * 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;   GList *Cookies;   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);      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->IOVec.iov_base+HdrLen, io->Status-HdrLen);      /* Free preallocated buffer */      if (io->Flags & IOFlag_FreeIOVec)         g_free(io->IOVec.iov_base);      /* Prepare next read */      io->IOVec.iov_base = (char *)entry->Data + entry->ValidSize;      io->IOVec.iov_len  = entry->TotalSize - entry->ValidSize;      io->Flags &= ~IOFlag_FreeIOVec;   } 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->IOVec.iov_base+HdrLen, entry->ValidSize);      /* Prepare next read */      if (io->Flags & IOFlag_FreeIOVec)         g_free(io->IOVec.iov_base);      io->IOVec.iov_base = (char *)entry->Data + entry->ValidSize;      io->IOVec.iov_len  = entry->BuffSize;      io->Flags &= ~IOFlag_FreeIOVec;   }   /* Get Content-Type */   if ( (Type = Cache_parse_field(header, "Content-Type")) == NULL ) {     DEBUG_HTTP_MSG("Server didn't send Content-Type in header.\n");     Type = Cache_get_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->IOVec.iov_base;   /* 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){         DEBUG_HTTP_MSG("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);

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -