Ejemplo n.º 1
0
/*
 * Read all the available data from a filedescriptor.
 * This is intended for short answers, i.e. when we know the server
 * will write it all before being preempted. For answers that may come
 * as an stream with delays, non-blocking is better.
 * Return value: read data, or NULL on error and no data.
 */
static char *Dpi_blocking_read(int fd)
{
   int st;
   const int buf_sz = 8*1024;
   char buf[buf_sz], *msg = NULL;
   Dstr *dstr = dStr_sized_new(buf_sz);

   do {
      st = read(fd, buf, buf_sz);
      if (st < 0) {
         if (errno == EINTR) {
            continue;
         } else {
            MSG_ERR("[Dpi_blocking_read] %s\n", dStrerror(errno));
            break;
         }
      } else if (st > 0) {
         dStr_append_l(dstr, buf, st);
      }
   } while (st == buf_sz);

   msg = (dstr->len > 0) ? dstr->str : NULL;
   dStr_free(dstr, (dstr->len > 0) ? FALSE : TRUE);
   return msg;
}
Ejemplo n.º 2
0
/*
 * Decode chunked data
 */
static Dstr *Decode_chunked(Decode *dc, const char *instr, int inlen)
{
   char *inputPtr, *eol;
   int inputRemaining;
   int chunkRemaining = *((int *)dc->state);
   Dstr *output = dStr_sized_new(inlen);

   dStr_append_l(dc->leftover, instr, inlen);
   inputPtr = dc->leftover->str;
   inputRemaining = dc->leftover->len;

   while (inputRemaining > 0) {
      if (chunkRemaining > 2) {
         /* chunk body to copy */
         int copylen = MIN(chunkRemaining - 2, inputRemaining);
         dStr_append_l(output, inputPtr, copylen);
         chunkRemaining -= copylen;
         inputRemaining -= copylen;
         inputPtr += copylen;
      }

      if ((chunkRemaining == 2) && (inputRemaining > 0)) {
         /* CR to discard */
         chunkRemaining--;
         inputRemaining--;
         inputPtr++;
      }
      if ((chunkRemaining == 1) && (inputRemaining > 0)) {
         /* LF to discard */
         chunkRemaining--;
         inputRemaining--;
         inputPtr++;
      }

      /*
       * A chunk has a one-line header that begins with the chunk length
       * in hexadecimal.
       */
      if (!(eol = (char *)memchr(inputPtr, '\n', inputRemaining))) {
         break;   /* We don't have the whole line yet. */
      }

      if (!(chunkRemaining = strtol(inputPtr, NULL, 0x10))) {
         break;   /* A chunk length of 0 means we're done! */
      }
      inputRemaining -= (eol - inputPtr) + 1;
      inputPtr = eol + 1;
      chunkRemaining += 2; /* CRLF at the end of every chunk */
   }

   /* If we have a partial chunk header, save it for next time. */
   dStr_erase(dc->leftover, 0, inputPtr - dc->leftover->str);

   *(int *)dc->state = chunkRemaining;
   return output;
}
Ejemplo n.º 3
0
Archivo: dpip.c Proyecto: epitron/dillo
/*
 * Create and initialize a dpip socket handler
 */
Dsh *a_Dpip_dsh_new(int fd_in, int fd_out, int flush_sz)
{
   Dsh *dsh = dNew(Dsh, 1);

   /* init descriptors and streams */
   dsh->fd_in  = fd_in;
   dsh->fd_out = fd_out;

   /* init buffer */
   dsh->wrbuf = dStr_sized_new(8 *1024);
   dsh->rdbuf = dStr_sized_new(8 *1024);
   dsh->flush_sz = flush_sz;
   dsh->mode = DPIP_TAG;
   if (fcntl(dsh->fd_in, F_GETFL) & O_NONBLOCK)
      dsh->mode |= DPIP_NONBLOCK;
   dsh->status = 0;

   return dsh;
}
Ejemplo n.º 4
0
/*
 * Escape characters as %XX sequences.
 * Return value: New string.
 */
char *a_Misc_escape_chars(const char *str, const char *esc_set)
{
   static const char *const hex = "0123456789ABCDEF";
   char *p = NULL;
   Dstr *dstr;
   int i;

   dstr = dStr_sized_new(64);
   for (i = 0; str[i]; ++i) {
      if (str[i] <= 0x1F || str[i] == 0x7F || strchr(esc_set, str[i])) {
         dStr_append_c(dstr, '%');
         dStr_append_c(dstr, hex[(str[i] >> 4) & 15]);
         dStr_append_c(dstr, hex[str[i] & 15]);
      } else {
Ejemplo n.º 5
0
/*
 * Escape URI characters in 'esc_set' as %XX sequences.
 * Return value: New escaped string.
 */
char *Escape_uri_str(const char *str, const char *p_esc_set)
{
   static const char *esc_set, *hex = "0123456789ABCDEF";
   char *p;
   Dstr *dstr;
   int i;

   esc_set = (p_esc_set) ? p_esc_set : "%#:' ";
   dstr = dStr_sized_new(64);
   for (i = 0; str[i]; ++i) {
      if (str[i] <= 0x1F || str[i] == 0x7F || strchr(esc_set, str[i])) {
         dStr_append_c(dstr, '%');
         dStr_append_c(dstr, hex[(str[i] >> 4) & 15]);
         dStr_append_c(dstr, hex[str[i] & 15]);
      } else {
Ejemplo n.º 6
0
Archivo: dpip.c Proyecto: epitron/dillo
/*
 * Printf like function for building dpip commands.
 * It takes care of dpip escaping of its arguments.
 * NOTE : It ONLY accepts string parameters, and
 *        only one %s per parameter.
 */
char *a_Dpip_build_cmd(const char *format, ...)
{
   va_list argp;
   char *p, *q, *s;
   Dstr *cmd;

   /* Don't allow Quote characters in attribute names */
   if (strchr(format, Quote))
      return NULL;

   cmd = dStr_sized_new(64);
   dStr_append_c(cmd, '<');
   va_start(argp, format);
   for (p = q = (char*)format; *q;  ) {
      p = strstr(q, "%s");
      if (!p) {
         dStr_append(cmd, q);
         break;
      } else {
         /* Copy format's part */
         while (q != p)
            dStr_append_c(cmd, *q++);
         q += 2;

         dStr_append_c(cmd, Quote);
         /* Stuff-copy of argument */
         s = va_arg (argp, char *);
         for (  ; *s; ++s) {
            dStr_append_c(cmd, *s);
            if (*s == Quote)
               dStr_append_c(cmd, *s);
         }
         dStr_append_c(cmd, Quote);
      }
   }
   va_end(argp);
   dStr_append_c(cmd, ' ');
   dStr_append_c(cmd, Quote);
   dStr_append_c(cmd, '>');

   p = cmd->str;
   dStr_free(cmd, FALSE);
   return p;
}
Ejemplo n.º 7
0
/*
 * Set safe values for a new cache entry
 */
static void Cache_entry_init(CacheEntry_t *NewEntry, const DilloUrl *Url)
{
   NewEntry->Url = a_Url_dup(Url);
   NewEntry->TypeDet = NULL;
   NewEntry->TypeHdr = NULL;
   NewEntry->TypeMeta = NULL;
   NewEntry->TypeNorm = NULL;
   NewEntry->Header = dStr_new("");
   NewEntry->Location = NULL;
   NewEntry->Auth = NULL;
   NewEntry->Data = dStr_sized_new(8*1024);
   NewEntry->UTF8Data = NULL;
   NewEntry->DataRefcount = 0;
   NewEntry->TransferDecoder = NULL;
   NewEntry->ContentDecoder = NULL;
   NewEntry->CharsetDecoder = NULL;
   NewEntry->ExpectedSize = 0;
   NewEntry->TransferSize = 0;
   NewEntry->Flags = CA_IsEmpty;
}
Ejemplo n.º 8
0
/*
 * Scan, allocate, and set things according to header info.
 * (This function needs the whole header to work)
 */
static void Cache_parse_header(CacheEntry_t *entry)
{
   char *header = entry->Header->str;
   char *Length, *Type, *location_str, *encoding;
#ifndef DISABLE_COOKIES
   Dlist *Cookies;
#endif
   Dlist *warnings;
   void *data;
   int i;

   _MSG("Cache_parse_header\n");

   if (entry->Header->len > 12) {
      if (header[9] == '1' && header[10] == '0' && header[11] == '0') {
         /* 100: Continue. The "real" header has not come yet. */
         MSG("An actual 100 Continue header!\n");
         entry->Flags &= ~CA_GotHeader;
         dStr_free(entry->Header, 1);
         entry->Header = dStr_new("");
         return;
      }
      if (header[9] == '3' && header[10] == '0' &&
          (location_str = Cache_parse_field(header, "Location"))) {
         /* 30x: URL redirection */
         DilloUrl *location_url = a_Url_new(location_str,URL_STR_(entry->Url));

         if (prefs.filter_auto_requests == PREFS_FILTER_SAME_DOMAIN &&
             !a_Url_same_organization(entry->Url, location_url)) {
            /* don't redirect; just show body like usual (if any) */
            MSG("Redirection not followed from %s to %s\n",
                URL_HOST(entry->Url), URL_STR(location_url));
            a_Url_free(location_url);
         } else {
            entry->Flags |= CA_Redirect;
            if (header[11] == '1')
               entry->Flags |= CA_ForceRedirect;  /* 301 Moved Permanently */
            else if (header[11] == '2')
               entry->Flags |= CA_TempRedirect;   /* 302 Temporary Redirect */

            if (URL_FLAGS(location_url) & (URL_Post + URL_Get) &&
                dStrAsciiCasecmp(URL_SCHEME(location_url), "dpi") == 0 &&
                dStrAsciiCasecmp(URL_SCHEME(entry->Url), "dpi") != 0) {
               /* Forbid dpi GET and POST from non dpi-generated urls */
               MSG("Redirection Denied! '%s' -> '%s'\n",
                   URL_STR(entry->Url), URL_STR(location_url));
               a_Url_free(location_url);
            } else {
               entry->Location = location_url;
            }
         }
         dFree(location_str);
      } else if (strncmp(header + 9, "401", 3) == 0) {
         entry->Auth =
            Cache_parse_multiple_fields(header, "WWW-Authenticate");
      } else if (strncmp(header + 9, "404", 3) == 0) {
         entry->Flags |= CA_NotFound;
      }
   }

   if ((warnings = Cache_parse_multiple_fields(header, "Warning"))) {
      for (i = 0; (data = dList_nth_data(warnings, i)); ++i) {
         MSG_HTTP("%s\n", (char *)data);
         dFree(data);
      }
      dList_free(warnings);
   }

   /*
    * Get Transfer-Encoding and initialize decoder
    */
   encoding = Cache_parse_field(header, "Transfer-Encoding");
   entry->TransferDecoder = a_Decode_transfer_init(encoding);


   if ((Length = Cache_parse_field(header, "Content-Length")) != NULL) {
      if (encoding) {
         /*
          * If Transfer-Encoding is present, Content-Length must be ignored.
          * If the Transfer-Encoding is non-identity, it is an error.
          */
         if (dStrAsciiCasecmp(encoding, "identity"))
            MSG_HTTP("Content-Length and non-identity Transfer-Encoding "
                     "headers both present.\n");
      } else {
         entry->Flags |= CA_GotLength;
         entry->ExpectedSize = MAX(strtol(Length, NULL, 10), 0);
      }
      dFree(Length);
   }

   dFree(encoding); /* free Transfer-Encoding */

#ifndef DISABLE_COOKIES
   if ((Cookies = Cache_parse_multiple_fields(header, "Set-Cookie"))) {
      CacheClient_t *client;

      for (i = 0; (client = dList_nth_data(ClientQueue, i)); ++i) {
         if (client->Url == entry->Url) {
            DilloWeb *web = client->Web;

            if (!web->requester ||
                a_Url_same_organization(entry->Url, web->requester)) {
               char *server_date = Cache_parse_field(header, "Date");

               a_Cookies_set(Cookies, entry->Url, server_date);
               dFree(server_date);
               break;
            }
         }
      }
      if (i >= dList_length(ClientQueue)) {
         MSG("Cache: cookies not accepted from '%s'\n", URL_STR(entry->Url));
      }

      for (i = 0; (data = dList_nth_data(Cookies, i)); ++i)
         dFree(data);
      dList_free(Cookies);
   }
#endif /* !DISABLE_COOKIES */

   /*
    * Get Content-Encoding and initialize decoder
    */
   encoding = Cache_parse_field(header, "Content-Encoding");
   entry->ContentDecoder = a_Decode_content_init(encoding);
   dFree(encoding);

   if (entry->ExpectedSize > 0) {
      if (entry->ExpectedSize > HUGE_FILESIZE) {
         entry->Flags |= CA_HugeFile;
      }
      /* Avoid some reallocs. With MAX_INIT_BUF we avoid a SEGFAULT
       * with huge files (e.g. iso files).
       * Note: the buffer grows automatically. */
      dStr_free(entry->Data, 1);
      entry->Data = dStr_sized_new(MIN(entry->ExpectedSize, MAX_INIT_BUF));
   }

   /* Get Content-Type */
   if ((Type = Cache_parse_field(header, "Content-Type"))) {
      /* This HTTP Content-Type is not trusted. It's checked against real data
       * in Cache_process_queue(); only then CA_GotContentType becomes true. */
      a_Cache_set_content_type(entry->Url, Type, "http");
      _MSG("TypeHdr  {%s} {%s}\n", Type, URL_STR(entry->Url));
      _MSG("TypeMeta {%s}\n", entry->TypeMeta);
      dFree(Type);
   }
   Cache_ref_data(entry);
}