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.
This commit is contained in:
Nick Mathewson 2017-08-08 12:07:25 -04:00
parent cddac959e7
commit f28e314b0d
5 changed files with 40 additions and 42 deletions

View File

@ -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.

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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);