Commit cd85eac0 authored by Nick Mathewson's avatar Nick Mathewson 🥔
Browse files

r17433@catbus: nickm | 2007-12-29 12:35:57 -0500

 Incomplete code to avoid doing needless pull-ups on HTTP.  Also, use memstr instead of strstr to find the content-length header.


svn:r13005
parent f4f5dc4a
Loading
Loading
Loading
Loading
+110 −2
Original line number Diff line number Diff line
@@ -943,6 +943,93 @@ move_buf_to_buf(buf_t *buf_out, buf_t *buf_in, size_t *buf_flushlen)
  return cp;
}

// #define BUFPOS
#ifdef BUFPOS
typedef struct buf_pos_t {
  chunk_t *chunk;
  int pos;
  int pos_absolute;
};

static void
buf_pos_init(buf_t *buf, buf_pos_t *out)
{
  out->chunk = buf->head;
  out->pos = 0;
  out->pos_absolute = 0;
}

static int
buf_find_pos_of_char(const buf_t *buf, char ch, buf_pos_t *out)
{
  chunk_t *chunk;
  int offset = 0;
  int pos = chunk->pos;
  for (chunk = out->chunk; chunk; chunk = chunk->next) {
    char *cp = memchr(chunk->data+pos, ch, chunk->datalen-pos);
    if (cp) {
      out->chunk = chunk;
      out->pos = cp - chunk->data;
      out->pos_absolute = offset + (cp - chunk->data);
      return out->pos_absolute;
    } else {
      offset += chunk->datalen;
      pos = 0;
    }
  }
  return -1;
}

static INLINE int
buf_pos_inc(buf_pos_t *pos)
{
  if (pos->pos == pos->chunk->datalen) {
    if (!pos->chunk->next)
      return -1;
    pos->chunk = pos->chunk->next;
    pos->pos = 0;
  } else {
    ++pos->pos;
  }
  ++pos->pos_absolute;
}

static int
buf_matches_at_pos(const buf_t *buf, const buf_pos_t *pos, const char *s,
                   int n)
{
  buf_pos_t p;
  memcpy(p, pos, sizeof(p));

  while (n) {
    char ch = p->chunk->data[p->pos];
    if (ch != *s)
      return 0;
    ++s;
    --n;
    if (buf_pos_inc(p)<0)
      return 0;
  }
  return 1;
}

static int
buf_find_string_offset(const char *buf, const char *s, int n)
{
  buf_pos_t pos;
  buf_pos_init(buf, &pos);
  while (buf_find_pos_of_char(buf, *s, &pos) >= 0) {
    if (buf_matches_at_pos(buf, pos, s, n)) {
      return pos->pos_absolute;
    } else {
      if (buf_pos_inc(pos)<0)
        return -1;
    }
  }
  return -1;
}
#endif

/** There is a (possibly incomplete) http statement on <b>buf</b>, of the
 * form "\%s\\r\\n\\r\\n\%s", headers, body. (body may contain nuls.)
 * If a) the headers include a Content-Length field and all bytes in
@@ -968,14 +1055,33 @@ fetch_from_buf_http(buf_t *buf,
                    char **body_out, size_t *body_used, size_t max_bodylen,
                    int force_complete)
{
  char *headers, *body, *p;
  char *headers, *p, *body;
  size_t headerlen, bodylen, contentlen;
#ifdef BUFPOS
  int crlf_offset;
#endif

  check();
  if (!buf->head)
    return 0;

  headers = buf->head->data;

#ifdef BUFPOS
  crlf_offset = buf_find_string_offset(buf, "\r\n\r\n", 4);
  if (crlf_offset > max_headerlen ||
      (crlf_offset < 0 && buf->datalen > max_headerlen)) {
    log_debug(LD_HTTP,"headers too long.");
    return -1;
  } else if (crlf_offset < 0) {
    log_debug(LD_HTTP,"headers not all here yet.");
    return 0;
  }
  if (buf->head->datalen < crlf_offset + 4)
    buf_pullup(buf, crlf_offset+4, 0);
  headerlen = crlf_offset + 4;
  body = buf->data + headerlen; /*XXX020 unused. */
#else
  /* See if CRLFCRLF is already in the head chunk.  If it is, we don't need
   * to move or resize anything. */
  body = (char*) tor_memmem(buf->head->data, buf->head->datalen,
@@ -1001,6 +1107,8 @@ fetch_from_buf_http(buf_t *buf,
  }
  body += 4; /* Skip the the CRLFCRLF */
  headerlen = body-headers; /* includes the CRLFCRLF */
#endif

  bodylen = buf->datalen - headerlen;
  log_debug(LD_HTTP,"headerlen %d, bodylen %d.", (int)headerlen, (int)bodylen);

@@ -1016,7 +1124,7 @@ fetch_from_buf_http(buf_t *buf,
  }

#define CONTENT_LENGTH "\r\nContent-Length: "
  p = strstr(headers, CONTENT_LENGTH);
  p = (char*) tor_memstr(headers, headerlen, CONTENT_LENGTH);
  if (p) {
    int i;
    i = atoi(p+strlen(CONTENT_LENGTH));