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

Make buf_pullup() expose the pulled-up data.

This lets us drop the testing-only function buf_get_first_chunk_data(),
and lets us implement proto_http and proto_socks without looking at
buf_t internals.
parent cddac959
Loading
Loading
Loading
Loading
+16 −16
Original line number Diff line number Diff line
@@ -203,22 +203,33 @@ preferred_chunk_size(size_t target)
/** Collapse data from the first N chunks from <b>buf</b> into buf->head,
 * growing it as necessary, until buf->head has the first <b>bytes</b> bytes
 * of data from the buffer, or until buf->head has all the data in <b>buf</b>.
 *
 * Set *<b>head_out</b> to point to the first byte of available data, and
 * *<b>len_out</b> to the number of bytes of data available at
 * *<b>head_out</b>. Note that *<b>len_out</b> may be more or less than
 * <b>bytes</b>, depending on the number of bytes available.
 */
void
buf_pullup(buf_t *buf, size_t bytes)
buf_pullup(buf_t *buf, size_t bytes, const char **head_out, size_t *len_out)
{
  chunk_t *dest, *src;
  size_t capacity;
  if (!buf->head)
  if (!buf->head) {
    *head_out = NULL;
    *len_out = 0;
    return;
  }

  check();
  if (buf->datalen < bytes)
    bytes = buf->datalen;

  capacity = bytes;
  if (buf->head->datalen >= bytes)
  if (buf->head->datalen >= bytes) {
    *head_out = buf->head->data;
    *len_out = buf->head->datalen;
    return;
  }

  if (buf->head->memlen >= capacity) {
    /* We don't need to grow the first chunk, but we might need to repack it.*/
@@ -263,22 +274,11 @@ buf_pullup(buf_t *buf, size_t bytes)
  }

  check();
  *head_out = buf->head->data;
  *len_out = buf->head->datalen;
}

#ifdef TOR_UNIT_TESTS
/* Return the data from the first chunk of buf in cp, and its length in sz. */
void
buf_get_first_chunk_data(const buf_t *buf, const char **cp, size_t *sz)
{
  if (!buf || !buf->head) {
    *cp = NULL;
    *sz = 0;
  } else {
    *cp = buf->head->data;
    *sz = buf->head->datalen;
  }
}

/* Write sz bytes from cp into a newly allocated buffer buf.
 * Returns NULL when passed a NULL cp or zero sz.
 * Asserts on failure: only for use in unit tests.
+2 −2
Original line number Diff line number Diff line
@@ -55,11 +55,11 @@ int buf_set_to_copy(buf_t **output,
void assert_buf_ok(buf_t *buf);

int buf_find_string_offset(const buf_t *buf, const char *s, size_t n);
void buf_pullup(buf_t *buf, size_t bytes);
void buf_pullup(buf_t *buf, size_t bytes,
                const char **head_out, size_t *len_out);

#ifdef BUFFERS_PRIVATE
#ifdef TOR_UNIT_TESTS
void buf_get_first_chunk_data(const buf_t *buf, const char **cp, size_t *sz);
buf_t *buf_new_with_data(const char *cp, size_t sz);
#endif
ATTR_UNUSED STATIC size_t preferred_chunk_size(size_t target);
+4 −6
Original line number Diff line number Diff line
@@ -4,7 +4,6 @@
 * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */

#define BUFFERS_PRIVATE // XXXX remove.
#define PROTO_HTTP_PRIVATE
#include "or.h"
#include "buffers.h"
@@ -48,12 +47,12 @@ fetch_from_buf_http(buf_t *buf,
                    char **body_out, size_t *body_used, size_t max_bodylen,
                    int force_complete)
{
  char *headers;
  const char *headers;
  size_t headerlen, bodylen, contentlen=0;
  int crlf_offset;
  int r;

  if (!buf->head)
  if (buf_datalen(buf) == 0)
    return 0;

  crlf_offset = buf_find_string_offset(buf, "\r\n\r\n", 4);
@@ -67,11 +66,10 @@ fetch_from_buf_http(buf_t *buf,
  }
  /* Okay, we have a full header.  Make sure it all appears in the first
   * chunk. */
  if ((int)buf->head->datalen < crlf_offset + 4)
    buf_pullup(buf, crlf_offset+4);
  headerlen = crlf_offset + 4;
  size_t headers_in_chunk = 0;
  buf_pullup(buf, headerlen, &headers, &headers_in_chunk);

  headers = buf->head->data;
  bodylen = buf_datalen(buf) - headerlen;
  log_debug(LD_HTTP,"headerlen %d, bodylen %d.", (int)headerlen, (int)bodylen);

+12 −8
Original line number Diff line number Diff line
@@ -4,7 +4,6 @@
 * Copyright (c) 2007-2017, The Tor Project, Inc. */
/* See LICENSE for licensing information */

#define BUFFERS_PRIVATE // XXXX remove.
#include "or.h"
#include "addressmap.h"
#include "buffers.h"
@@ -115,17 +114,19 @@ fetch_from_buf_socks(buf_t *buf, socks_request_t *req,
  int res;
  ssize_t n_drain;
  size_t want_length = 128;
  const char *head = NULL;
  size_t datalen = 0;

  if (buf_datalen(buf) < 2) /* version and another byte */
    return 0;

  do {
    n_drain = 0;
    buf_pullup(buf, want_length);
    tor_assert(buf->head && buf->head->datalen >= 2);
    buf_pullup(buf, want_length, &head, &datalen);
    tor_assert(head && datalen >= 2);
    want_length = 0;

    res = parse_socks(buf->head->data, buf->head->datalen, req, log_sockstype,
    res = parse_socks(head, datalen, req, log_sockstype,
                      safe_socks, &n_drain, &want_length);

    if (n_drain < 0)
@@ -133,7 +134,7 @@ fetch_from_buf_socks(buf_t *buf, socks_request_t *req,
    else if (n_drain > 0)
      buf_remove_from_front(buf, n_drain);

  } while (res == 0 && buf->head && want_length < buf_datalen(buf) &&
  } while (res == 0 && head && want_length < buf_datalen(buf) &&
           buf_datalen(buf) >= 2);

  return res;
@@ -591,13 +592,16 @@ fetch_from_buf_socks_client(buf_t *buf, int state, char **reason)
{
  ssize_t drain = 0;
  int r;
  const char *head = NULL;
  size_t datalen = 0;

  if (buf_datalen(buf) < 2)
    return 0;

  buf_pullup(buf, MAX_SOCKS_MESSAGE_LEN);
  tor_assert(buf->head && buf->head->datalen >= 2);
  buf_pullup(buf, MAX_SOCKS_MESSAGE_LEN, &head, &datalen);
  tor_assert(head && datalen >= 2);

  r = parse_socks_client((uint8_t*)buf->head->data, buf->head->datalen,
  r = parse_socks_client((uint8_t*)head, datalen,
                         state, reason, &drain);
  if (drain > 0)
    buf_remove_from_front(buf, drain);
+6 −10
Original line number Diff line number Diff line
@@ -220,8 +220,7 @@ test_buffer_pullup(void *arg)

  /* There are a bunch of cases for pullup.  One is the trivial case. Let's
     mess around with an empty buffer. */
  buf_pullup(buf, 16);
  buf_get_first_chunk_data(buf, &cp, &sz);
  buf_pullup(buf, 16, &cp, &sz);
  tt_ptr_op(cp, OP_EQ, NULL);
  tt_uint_op(sz, OP_EQ, 0);

@@ -234,7 +233,7 @@ test_buffer_pullup(void *arg)
  crypto_rand(stuff, 16384);
  write_to_buf(stuff, 3000, buf);
  write_to_buf(stuff+3000, 3000, buf);
  buf_get_first_chunk_data(buf, &cp, &sz);
  buf_pullup(buf, 0, &cp, &sz);
  tt_ptr_op(cp, OP_NE, NULL);
  tt_int_op(sz, OP_LE, 4096);

@@ -242,9 +241,8 @@ test_buffer_pullup(void *arg)
   * can get tested. */
  tt_int_op(fetch_from_buf(tmp, 3000, buf), OP_EQ, 3000);
  tt_mem_op(tmp,OP_EQ, stuff, 3000);
  buf_pullup(buf, 2048);
  buf_pullup(buf, 2048, &cp, &sz);
  assert_buf_ok(buf);
  buf_get_first_chunk_data(buf, &cp, &sz);
  tt_ptr_op(cp, OP_NE, NULL);
  tt_int_op(sz, OP_GE, 2048);
  tt_mem_op(cp,OP_EQ, stuff+3000, 2048);
@@ -261,13 +259,12 @@ test_buffer_pullup(void *arg)
  write_to_buf(stuff+8000, 4000, buf);
  write_to_buf(stuff+12000, 4000, buf);
  tt_int_op(buf_datalen(buf), OP_EQ, 16000);
  buf_get_first_chunk_data(buf, &cp, &sz);
  buf_pullup(buf, 0, &cp, &sz);
  tt_ptr_op(cp, OP_NE, NULL);
  tt_int_op(sz, OP_LE, 4096);

  buf_pullup(buf, 12500);
  buf_pullup(buf, 12500, &cp, &sz);
  assert_buf_ok(buf);
  buf_get_first_chunk_data(buf, &cp, &sz);
  tt_ptr_op(cp, OP_NE, NULL);
  tt_int_op(sz, OP_GE, 12500);
  tt_mem_op(cp,OP_EQ, stuff, 12500);
@@ -288,9 +285,8 @@ test_buffer_pullup(void *arg)
  write_to_buf(stuff, 4000, buf);
  write_to_buf(stuff+4000, 4000, buf);
  fetch_from_buf(tmp, 100, buf); /* dump 100 bytes from first chunk */
  buf_pullup(buf, 16000); /* Way too much. */
  buf_pullup(buf, 16000, &cp, &sz);
  assert_buf_ok(buf);
  buf_get_first_chunk_data(buf, &cp, &sz);
  tt_ptr_op(cp, OP_NE, NULL);
  tt_int_op(sz, OP_EQ, 7900);
  tt_mem_op(cp,OP_EQ, stuff+100, 7900);