Example #1
0
/*
 * Consume bytes until the whole header is got (up to a "\r\n\r\n" sequence)
 * (Also unfold multi-line fields and strip '\r' chars from header)
 */
static int Cache_get_header(CacheEntry_t *entry,
                            const char *buf, size_t buf_size)
{
   size_t N, i;
   Dstr *hdr = entry->Header;

   /* Header finishes when N = 2 */
   N = (hdr->len && hdr->str[hdr->len - 1] == '\n');
   for (i = 0; i < buf_size && N < 2; ++i) {
      if (buf[i] == '\r' || !buf[i])
         continue;
      if (N == 1 && (buf[i] == ' ' || buf[i] == '\t')) {
         /* unfold multiple-line header */
         _MSG("Multiple-line header!\n");
         dStr_erase(hdr, hdr->len - 1, 1);
      }
      N = (buf[i] == '\n') ? N + 1 : 0;
      dStr_append_c(hdr, buf[i]);
   }

   if (N == 2) {
      /* Got whole header */
      _MSG("Header [buf_size=%d]\n%s", i, hdr->str);
      entry->Flags |= CA_GotHeader;
      dStr_fit(hdr);
      /* Return number of header bytes in 'buf' [1 based] */
      return i;
   }
   return 0;
}
Example #2
0
/*
 * Inject full page content directly into the cache.
 * Used for "about:splash". May be used for "about:cache" too.
 */
static void Cache_entry_inject(const DilloUrl *Url, Dstr *data_ds)
{
   CacheEntry_t *entry;

   if (!(entry = Cache_entry_search(Url)))
      entry = Cache_entry_add(Url);
   entry->Flags |= CA_GotData + CA_GotHeader + CA_GotLength + CA_InternalUrl;
   if (data_ds->len)
      entry->Flags &= ~CA_IsEmpty;
   dStr_truncate(entry->Data, 0);
   dStr_append_l(entry->Data, data_ds->str, data_ds->len);
   dStr_fit(entry->Data);
   entry->ExpectedSize = entry->TransferSize = entry->Data->len;
}
Example #3
0
static void Cache_finish_msg(CacheEntry_t *entry)
{
   if (entry->Flags & CA_GotData) {
      /* already finished */
      return;
   }

   if ((entry->ExpectedSize || entry->TransferSize) &&
       entry->TypeHdr == NULL) {
      MSG_HTTP("Message with a body lacked Content-Type header.\n");
   }
   if ((entry->Flags & CA_GotLength) &&
       (entry->ExpectedSize != entry->TransferSize)) {
      MSG_HTTP("Content-Length does NOT match message body at\n"
               "%s\n", URL_STR_(entry->Url));
      MSG("Expected size: %d, Transfer size: %d\n",
          entry->ExpectedSize, entry->TransferSize);
   }
   entry->Flags |= CA_GotData;
   entry->Flags &= ~CA_Stopped;          /* it may catch up! */
   if (entry->TransferDecoder) {
      a_Decode_transfer_free(entry->TransferDecoder);
      entry->TransferDecoder = NULL;
   }
   if (entry->ContentDecoder) {
      a_Decode_free(entry->ContentDecoder);
      entry->ContentDecoder = NULL;
   }
   dStr_fit(entry->Data);                /* fit buffer size! */

   if ((entry = Cache_process_queue(entry))) {
      if (entry->Flags & CA_GotHeader) {
         Cache_unref_data(entry);
      }
   }
}
Example #4
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
 */
void a_Cache_process_dbuf(int Op, const char *buf, size_t buf_size,
                          const DilloUrl *Url)
{
   int offset, len;
   const char *str;
   Dstr *dstr1, *dstr2, *dstr3;
   CacheEntry_t *entry = Cache_entry_search(Url);

   /* Assert a valid entry (not aborted) */
   dReturn_if_fail (entry != NULL);

   _MSG("__a_Cache_process_dbuf__\n");

   if (Op == IORead) {
      /*
       * Cache_get_header() will set CA_GotHeader if it has a full header, and
       * Cache_parse_header() will unset it if the header ends being
       * merely an informational response from the server (i.e., 100 Continue)
       */
      for (offset = 0; !(entry->Flags & CA_GotHeader) &&
           (len = Cache_get_header(entry, buf + offset, buf_size - offset));
           Cache_parse_header(entry) ) {
         offset += len;
      }

      if (entry->Flags & CA_GotHeader) {
         str = buf + offset;
         len = buf_size - offset;
         entry->TransferSize += len;
         dstr1 = dstr2 = dstr3 = NULL;

         /* Decode arrived data (<= 3 stages) */
         if (entry->TransferDecoder) {
            dstr1 = a_Decode_process(entry->TransferDecoder, str, len);
            str = dstr1->str;
            len = dstr1->len;
         }
         if (entry->ContentDecoder) {
            dstr2 = a_Decode_process(entry->ContentDecoder, str, len);
            str = dstr2->str;
            len = dstr2->len;
         }
         dStr_append_l(entry->Data, str, len);
         if (entry->CharsetDecoder && entry->UTF8Data) {
            dstr3 = a_Decode_process(entry->CharsetDecoder, str, len);
            dStr_append_l(entry->UTF8Data, dstr3->str, dstr3->len);
         }
         dStr_free(dstr1, 1);
         dStr_free(dstr2, 1);
         dStr_free(dstr3, 1);

         if (entry->Data->len)
            entry->Flags &= ~CA_IsEmpty;

         entry = Cache_process_queue(entry);
      }
   } else if (Op == IOClose) {
      if ((entry->ExpectedSize || entry->TransferSize) &&
          entry->TypeHdr == NULL) {
         MSG_HTTP("Message with a body lacked Content-Type header.\n");
      }
      if ((entry->Flags & CA_GotLength) &&
          (entry->ExpectedSize != entry->TransferSize)) {
         MSG_HTTP("Content-Length does NOT match message body,\n"
                  " at: %s\n", URL_STR_(entry->Url));
         MSG("entry->ExpectedSize = %d, entry->TransferSize = %d\n",
             entry->ExpectedSize, entry->TransferSize);
      }
      if (!entry->TransferSize && !(entry->Flags & CA_Redirect) &&
          (entry->Flags & WEB_RootUrl)) {
         char *eol = strchr(entry->Header->str, '\n');
         if (eol) {
            char *status_line = dStrndup(entry->Header->str,
                                         eol - entry->Header->str);
            MSG_HTTP("Body was empty. Server sent status: %s\n", status_line);
            dFree(status_line);
         }
      }
      entry->Flags |= CA_GotData;
      entry->Flags &= ~CA_Stopped;          /* it may catch up! */
      if (entry->TransferDecoder) {
         a_Decode_free(entry->TransferDecoder);
         entry->TransferDecoder = NULL;
      }
      if (entry->ContentDecoder) {
         a_Decode_free(entry->ContentDecoder);
         entry->ContentDecoder = NULL;
      }
      dStr_fit(entry->Data);                /* fit buffer size! */

      if ((entry = Cache_process_queue(entry))) {
         if (entry->Flags & CA_GotHeader) {
            Cache_unref_data(entry);
         }
      }
   } else if (Op == IOAbort) {
      /* unused */
      MSG("a_Cache_process_dbuf Op = IOAbort; not implemented!\n");
   }
}