transition part of http_parser to use span (#936)

transition parts of http_parser to use span
This commit is contained in:
Arvid Norberg 2016-07-24 00:52:20 -07:00 committed by GitHub
parent ec30daeaa5
commit 4f803353cf
16 changed files with 152 additions and 173 deletions

View File

@ -55,7 +55,7 @@ namespace libtorrent { namespace aux
ret <<= 8; ret <<= 8;
ret |= static_cast<std::uint8_t>(view[i]); ret |= static_cast<std::uint8_t>(view[i]);
} }
view = view.cut_first(sizeof(T)); view = view.subspan(sizeof(T));
return ret; return ret;
} }
@ -69,7 +69,7 @@ namespace libtorrent { namespace aux
shift -= 8; shift -= 8;
view[i] = static_cast<unsigned char>((val >> shift) & 0xff); view[i] = static_cast<unsigned char>((val >> shift) & 0xff);
} }
view = view.cut_first(sizeof(T)); view = view.subspan(sizeof(T));
} }
// -- adaptors // -- adaptors

View File

@ -75,6 +75,7 @@ class buffer
{ {
public: public:
// TODO: 3 remove interval and const_interval
struct interval struct interval
{ {
interval() interval()
@ -208,20 +209,8 @@ public:
~buffer() { std::free(m_begin); } ~buffer() { std::free(m_begin); }
// TODO: 3 fix the naming convention here char* data() { return m_begin; }
char* ptr() { return m_begin; } char const* data() const { return m_begin; }
char const* ptr() const { return m_begin; }
buffer::interval data()
{ return interval(m_begin, m_begin + m_size); }
buffer::const_interval data() const
{ return interval(m_begin, m_begin + m_size); }
operator span<char>()
{ return span<char>(m_begin, int(m_size)); }
operator span<char const>() const
{ return span<char const>(m_begin, int(m_size)); }
std::size_t size() const { return m_size; } std::size_t size() const { return m_size; }
bool empty() const { return m_size == 0; } bool empty() const { return m_size == 0; }
@ -239,6 +228,7 @@ public:
swap(m_begin, b.m_begin); swap(m_begin, b.m_begin);
swap(m_size, b.m_size); swap(m_size, b.m_size);
} }
private: private:
char* m_begin = nullptr; char* m_begin = nullptr;
// m_begin points to an allocation of this size. // m_begin points to an allocation of this size.

View File

@ -77,7 +77,7 @@ namespace libtorrent
buffer::const_interval get_body() const; buffer::const_interval get_body() const;
bool header_finished() const { return m_state == read_body; } bool header_finished() const { return m_state == read_body; }
bool finished() const { return m_finished; } bool finished() const { return m_finished; }
std::tuple<int, int> incoming(buffer::const_interval recv_buffer std::tuple<int, int> incoming(span<char const> recv_buffer
, bool& error); , bool& error);
int body_start() const { return m_body_start_pos; } int body_start() const { return m_body_start_pos; }
std::int64_t content_length() const { return m_content_length; } std::int64_t content_length() const { return m_content_length; }
@ -110,7 +110,7 @@ namespace libtorrent
// if the function returns false, the chunk size and header // if the function returns false, the chunk size and header
// size may still have been modified, but their values are // size may still have been modified, but their values are
// undefined // undefined
bool parse_chunk_header(buffer::const_interval buf bool parse_chunk_header(span<char const> buf
, std::int64_t* chunk_size, int* header_size); , std::int64_t* chunk_size, int* header_size);
// reset the whole state and start over // reset the whole state and start over
@ -122,18 +122,18 @@ namespace libtorrent
std::vector<std::pair<std::int64_t, std::int64_t> > const& chunks() const { return m_chunked_ranges; } std::vector<std::pair<std::int64_t, std::int64_t> > const& chunks() const { return m_chunked_ranges; }
private: private:
std::int64_t m_recv_pos; std::int64_t m_recv_pos = 0;
std::string m_method; std::string m_method;
std::string m_path; std::string m_path;
std::string m_protocol; std::string m_protocol;
std::string m_server_message; std::string m_server_message;
std::int64_t m_content_length; std::int64_t m_content_length = -1;
std::int64_t m_range_start; std::int64_t m_range_start = -1;
std::int64_t m_range_end; std::int64_t m_range_end = -1;
std::multimap<std::string, std::string> m_header; std::multimap<std::string, std::string> m_header;
buffer::const_interval m_recv_buffer; span<char const> m_recv_buffer;
// contains offsets of the first and one-past-end of // contains offsets of the first and one-past-end of
// each chunked range in the response // each chunked range in the response
std::vector<std::pair<std::int64_t, std::int64_t> > m_chunked_ranges; std::vector<std::pair<std::int64_t, std::int64_t> > m_chunked_ranges;
@ -141,27 +141,27 @@ namespace libtorrent
// while reading a chunk, this is the offset where the // while reading a chunk, this is the offset where the
// current chunk will end (it refers to the first character // current chunk will end (it refers to the first character
// in the chunk tail header or the next chunk header) // in the chunk tail header or the next chunk header)
std::int64_t m_cur_chunk_end; std::int64_t m_cur_chunk_end = -1;
int m_status_code; int m_status_code = -1;
// the sum of all chunk headers read so far // the sum of all chunk headers read so far
int m_chunk_header_size; int m_chunk_header_size = 0;
int m_partial_chunk_header; int m_partial_chunk_header = 0;
// controls some behaviors of the parser // controls some behaviors of the parser
int m_flags; int m_flags;
int m_body_start_pos; int m_body_start_pos = 0;
enum { read_status, read_header, read_body, error_state } m_state; enum { read_status, read_header, read_body, error_state } m_state = read_status;
// this is true if the server is HTTP/1.0 or // this is true if the server is HTTP/1.0 or
// if it sent "connection: close" // if it sent "connection: close"
bool m_connection_close; bool m_connection_close = false;
bool m_chunked_encoding; bool m_chunked_encoding = false;
bool m_finished; bool m_finished = false;
}; };
} }

View File

@ -85,6 +85,7 @@ struct TORRENT_EXTRA_EXPORT receive_buffer
// return the interval between the start of the buffer to the read cursor. // return the interval between the start of the buffer to the read cursor.
// This is the "current" packet. // This is the "current" packet.
// TODO: 3 use span
buffer::const_interval get() const; buffer::const_interval get() const;
#if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS) #if !defined(TORRENT_DISABLE_ENCRYPTION) && !defined(TORRENT_DISABLE_EXTENSIONS)
@ -198,6 +199,7 @@ struct crypto_receive_buffer
int advance_pos(int bytes); int advance_pos(int bytes);
// TODO: 3 use span
buffer::const_interval get() const; buffer::const_interval get() const;
aux::mutable_buffer mutable_buffer(std::size_t bytes); aux::mutable_buffer mutable_buffer(std::size_t bytes);

View File

@ -92,10 +92,17 @@ namespace libtorrent
return { data() + size() - n, n }; return { data() + size() - n, n };
} }
span<T> cut_first(size_t const n) const span<T> subspan(size_t const offset) const
{ {
TORRENT_ASSERT(size() >= n); TORRENT_ASSERT(size() >= offset);
return { data() + n, int(size()) - n }; return { data() + offset, size() - offset };
}
span<T> subspan(size_t const offset, size_t count) const
{
TORRENT_ASSERT(size() >= offset);
TORRENT_ASSERT(size() >= offset + count);
return { data() + offset, count };
} }
T& operator[](size_t const idx) T& operator[](size_t const idx)

View File

@ -743,10 +743,9 @@ void http_connection::on_read(error_code const& e
if (m_bottled || !m_parser.header_finished()) if (m_bottled || !m_parser.header_finished())
{ {
libtorrent::buffer::const_interval rcv_buf(&m_recvbuffer[0] span<char const> rcv_buf(m_recvbuffer);
, &m_recvbuffer[0] + m_read_pos);
bool error = false; bool error = false;
m_parser.incoming(rcv_buf, error); m_parser.incoming(rcv_buf.subspan(0, m_read_pos), error);
if (error) if (error)
{ {
// HTTP parse error // HTTP parse error

View File

@ -132,33 +132,17 @@ namespace libtorrent
http_parser::~http_parser() = default; http_parser::~http_parser() = default;
http_parser::http_parser(int flags) http_parser::http_parser(int const flags) : m_flags(flags) {}
: m_recv_pos(0)
, m_content_length(-1)
, m_range_start(-1)
, m_range_end(-1)
, m_recv_buffer(nullptr, nullptr)
, m_cur_chunk_end(-1)
, m_status_code(-1)
, m_chunk_header_size(0)
, m_partial_chunk_header(0)
, m_flags(flags)
, m_body_start_pos(0)
, m_state(read_status)
, m_connection_close(false)
, m_chunked_encoding(false)
, m_finished(false)
{}
std::tuple<int, int> http_parser::incoming( std::tuple<int, int> http_parser::incoming(
buffer::const_interval recv_buffer, bool& error) span<char const> recv_buffer, bool& error)
{ {
TORRENT_ASSERT(recv_buffer.left() >= m_recv_buffer.left()); TORRENT_ASSERT(recv_buffer.size() >= m_recv_buffer.size());
std::tuple<int, int> ret(0, 0); std::tuple<int, int> ret(0, 0);
int start_pos = m_recv_buffer.left(); size_t start_pos = m_recv_buffer.size();
// early exit if there's nothing new in the receive buffer // early exit if there's nothing new in the receive buffer
if (start_pos == recv_buffer.left()) return ret; if (start_pos == recv_buffer.size()) return ret;
m_recv_buffer = recv_buffer; m_recv_buffer = recv_buffer;
if (m_state == error_state) if (m_state == error_state)
@ -167,19 +151,19 @@ namespace libtorrent
return ret; return ret;
} }
char const* pos = recv_buffer.begin + m_recv_pos; char const* pos = recv_buffer.data() + m_recv_pos;
restart_response: restart_response:
if (m_state == read_status) if (m_state == read_status)
{ {
TORRENT_ASSERT(!m_finished); TORRENT_ASSERT(!m_finished);
TORRENT_ASSERT(pos <= recv_buffer.end); TORRENT_ASSERT(pos <= recv_buffer.end());
char const* newline = std::find(pos, recv_buffer.end, '\n'); char const* newline = std::find(pos, recv_buffer.end(), '\n');
// if we don't have a full line yet, wait. // if we don't have a full line yet, wait.
if (newline == recv_buffer.end) if (newline == recv_buffer.end())
{ {
std::get<1>(ret) += m_recv_buffer.left() - start_pos; std::get<1>(ret) += int(m_recv_buffer.size() - start_pos);
return ret; return ret;
} }
@ -198,7 +182,7 @@ restart_response:
TORRENT_ASSERT(newline >= pos); TORRENT_ASSERT(newline >= pos);
int incoming = int(newline - pos); int incoming = int(newline - pos);
m_recv_pos += incoming; m_recv_pos += incoming;
std::get<1>(ret) += newline - (m_recv_buffer.begin + start_pos); std::get<1>(ret) += int(newline - (m_recv_buffer.data() + start_pos));
pos = newline; pos = newline;
m_protocol = read_until(line, ' ', line_end); m_protocol = read_until(line, ' ', line_end);
@ -223,17 +207,17 @@ restart_response:
m_status_code = 0; m_status_code = 0;
} }
m_state = read_header; m_state = read_header;
start_pos = pos - recv_buffer.begin; start_pos = pos - recv_buffer.data();
} }
if (m_state == read_header) if (m_state == read_header)
{ {
TORRENT_ASSERT(!m_finished); TORRENT_ASSERT(!m_finished);
TORRENT_ASSERT(pos <= recv_buffer.end); TORRENT_ASSERT(pos <= recv_buffer.end());
char const* newline = std::find(pos, recv_buffer.end, '\n'); char const* newline = std::find(pos, recv_buffer.end(), '\n');
std::string line; std::string line;
while (newline != recv_buffer.end && m_state == read_header) while (newline != recv_buffer.end() && m_state == read_header)
{ {
// if the LF character is preceeded by a CR // if the LF character is preceeded by a CR
// charachter, don't copy it into the line string. // charachter, don't copy it into the line string.
@ -338,16 +322,16 @@ restart_response:
m_chunked_encoding = string_begins_no_case("chunked", value.c_str()); m_chunked_encoding = string_begins_no_case("chunked", value.c_str());
} }
TORRENT_ASSERT(m_recv_pos <= recv_buffer.left()); TORRENT_ASSERT(m_recv_pos <= recv_buffer.size());
TORRENT_ASSERT(pos <= recv_buffer.end); TORRENT_ASSERT(pos <= recv_buffer.end());
newline = std::find(pos, recv_buffer.end, '\n'); newline = std::find(pos, recv_buffer.end(), '\n');
} }
std::get<1>(ret) += newline - (m_recv_buffer.begin + start_pos); std::get<1>(ret) += int(newline - (m_recv_buffer.data() + start_pos));
} }
if (m_state == read_body) if (m_state == read_body)
{ {
int incoming = recv_buffer.end - pos; int incoming = recv_buffer.end() - pos;
if (m_chunked_encoding && (m_flags & dont_parse_chunks) == 0) if (m_chunked_encoding && (m_flags & dont_parse_chunks) == 0)
{ {
@ -364,7 +348,8 @@ restart_response:
std::get<0>(ret) += int(payload); std::get<0>(ret) += int(payload);
incoming -= int(payload); incoming -= int(payload);
} }
buffer::const_interval buf(recv_buffer.begin + m_cur_chunk_end, recv_buffer.end); auto const buf = span<char const>(recv_buffer)
.subspan(m_cur_chunk_end);
std::int64_t chunk_size; std::int64_t chunk_size;
int header_size; int header_size;
if (parse_chunk_header(buf, &chunk_size, &header_size)) if (parse_chunk_header(buf, &chunk_size, &header_size))
@ -393,7 +378,7 @@ restart_response:
// std::fprintf(stderr, "parse_chunk_header(%d, -> %d, -> %d) -> %d\n" // std::fprintf(stderr, "parse_chunk_header(%d, -> %d, -> %d) -> %d\n"
// " incoming = %d\n m_recv_pos = %d\n m_cur_chunk_end = %d\n" // " incoming = %d\n m_recv_pos = %d\n m_cur_chunk_end = %d\n"
// " content-length = %d\n" // " content-length = %d\n"
// , buf.left(), int(chunk_size), header_size, 1, incoming, int(m_recv_pos) // , buf.size(), int(chunk_size), header_size, 1, incoming, int(m_recv_pos)
// , m_cur_chunk_end, int(m_content_length)); // , m_cur_chunk_end, int(m_content_length));
} }
else else
@ -404,7 +389,7 @@ restart_response:
// std::fprintf(stderr, "parse_chunk_header(%d, -> %d, -> %d) -> %d\n" // std::fprintf(stderr, "parse_chunk_header(%d, -> %d, -> %d) -> %d\n"
// " incoming = %d\n m_recv_pos = %d\n m_cur_chunk_end = %d\n" // " incoming = %d\n m_recv_pos = %d\n m_cur_chunk_end = %d\n"
// " content-length = %d\n" // " content-length = %d\n"
// , buf.left(), int(chunk_size), header_size, 0, incoming, int(m_recv_pos) // , buf.size(), int(chunk_size), header_size, 0, incoming, int(m_recv_pos)
// , m_cur_chunk_end, int(m_content_length)); // , m_cur_chunk_end, int(m_content_length));
} }
m_chunk_header_size += header_size; m_chunk_header_size += header_size;
@ -445,23 +430,22 @@ restart_response:
return ret; return ret;
} }
bool http_parser::parse_chunk_header(buffer::const_interval buf bool http_parser::parse_chunk_header(span<char const> buf
, std::int64_t* chunk_size, int* header_size) , std::int64_t* chunk_size, int* header_size)
{ {
TORRENT_ASSERT(buf.begin <= buf.end); char const* pos = buf.data();
char const* pos = buf.begin;
// ignore one optional new-line. This is since each chunk // ignore one optional new-line. This is since each chunk
// is terminated by a newline. we're likely to see one // is terminated by a newline. we're likely to see one
// before the actual header. // before the actual header.
if (pos < buf.end && pos[0] == '\r') ++pos; if (pos < buf.end() && pos[0] == '\r') ++pos;
if (pos < buf.end && pos[0] == '\n') ++pos; if (pos < buf.end() && pos[0] == '\n') ++pos;
if (pos == buf.end) return false; if (pos == buf.end()) return false;
TORRENT_ASSERT(pos <= buf.end); TORRENT_ASSERT(pos <= buf.end());
char const* newline = std::find(pos, buf.end, '\n'); char const* newline = std::find(pos, buf.end(), '\n');
if (newline == buf.end) return false; if (newline == buf.end()) return false;
++newline; ++newline;
// the chunk header is a single line, a hex length of the // the chunk header is a single line, a hex length of the
@ -476,19 +460,19 @@ restart_response:
if (*chunk_size != 0) if (*chunk_size != 0)
{ {
*header_size = newline - buf.begin; *header_size = newline - buf.data();
// the newline alone is two bytes // the newline alone is two bytes
TORRENT_ASSERT(newline - buf.begin > 2); TORRENT_ASSERT(newline - buf.data() > 2);
return true; return true;
} }
// this is the terminator of the stream. Also read headers // this is the terminator of the stream. Also read headers
std::map<std::string, std::string> tail_headers; std::map<std::string, std::string> tail_headers;
pos = newline; pos = newline;
newline = std::find(pos, buf.end, '\n'); newline = std::find(pos, buf.end(), '\n');
std::string line; std::string line;
while (newline != buf.end) while (newline != buf.end())
{ {
// if the LF character is preceeded by a CR // if the LF character is preceeded by a CR
// charachter, don't copy it into the line string. // charachter, don't copy it into the line string.
@ -504,10 +488,10 @@ restart_response:
// this means we got a blank line, // this means we got a blank line,
// the header is finished and the body // the header is finished and the body
// starts. // starts.
*header_size = newline - buf.begin; *header_size = newline - buf.data();
// the newline alone is two bytes // the newline alone is two bytes
TORRENT_ASSERT(newline - buf.begin > 2); TORRENT_ASSERT(newline - buf.data() > 2);
// we were successfull in parsing the headers. // we were successfull in parsing the headers.
// add them to the headers in the parser // add them to the headers in the parser
@ -529,7 +513,7 @@ restart_response:
tail_headers.insert(std::make_pair(name, value)); tail_headers.insert(std::make_pair(name, value));
// std::fprintf(stderr, "tail_header: %s: %s\n", name.c_str(), value.c_str()); // std::fprintf(stderr, "tail_header: %s: %s\n", name.c_str(), value.c_str());
newline = std::find(pos, buf.end, '\n'); newline = std::find(pos, buf.end(), '\n');
} }
return false; return false;
} }
@ -543,8 +527,9 @@ restart_response:
? m_recv_pos : (std::min)(m_body_start_pos + m_content_length, m_recv_pos); ? m_recv_pos : (std::min)(m_body_start_pos + m_content_length, m_recv_pos);
TORRENT_ASSERT(last_byte >= m_body_start_pos); TORRENT_ASSERT(last_byte >= m_body_start_pos);
return buffer::const_interval(m_recv_buffer.begin + m_body_start_pos return buffer::const_interval(m_recv_buffer.data()
, m_recv_buffer.begin + last_byte); + m_body_start_pos
, m_recv_buffer.data() + last_byte);
} }
void http_parser::reset() void http_parser::reset()
@ -558,8 +543,7 @@ restart_response:
m_range_end = -1; m_range_end = -1;
m_finished = false; m_finished = false;
m_state = read_status; m_state = read_status;
m_recv_buffer.begin = nullptr; m_recv_buffer = span<char const>();
m_recv_buffer.end = nullptr;
m_header.clear(); m_header.clear();
m_chunked_encoding = false; m_chunked_encoding = false;
m_chunked_ranges.clear(); m_chunked_ranges.clear();

View File

@ -247,7 +247,8 @@ namespace libtorrent
bool parse_error = false; bool parse_error = false;
int protocol = 0; int protocol = 0;
int payload = 0; int payload = 0;
std::tie(payload, protocol) = m_parser.incoming(recv_buffer, parse_error); std::tie(payload, protocol) = m_parser.incoming(span<char const>(
recv_buffer.begin, recv_buffer.left()), parse_error);
received_bytes(0, protocol); received_bytes(0, protocol);
bytes_transferred -= protocol; bytes_transferred -= protocol;
#if TORRENT_USE_ASSERTS #if TORRENT_USE_ASSERTS
@ -362,17 +363,16 @@ namespace libtorrent
{ {
int header_size = 0; int header_size = 0;
std::int64_t chunk_size = 0; std::int64_t chunk_size = 0;
buffer::const_interval chunk_start = recv_buffer; span<char const> chunk_start(recv_buffer.begin + m_chunk_pos, recv_buffer.left() - m_chunk_pos);
chunk_start.begin += m_chunk_pos; TORRENT_ASSERT(chunk_start[0] == '\r'
TORRENT_ASSERT(chunk_start.begin[0] == '\r' || aux::is_hex(chunk_start.data(), 1));
|| aux::is_hex(chunk_start.begin, 1));
bool ret = m_parser.parse_chunk_header(chunk_start, &chunk_size, &header_size); bool ret = m_parser.parse_chunk_header(chunk_start, &chunk_size, &header_size);
if (!ret) if (!ret)
{ {
TORRENT_ASSERT(bytes_transferred >= size_t(chunk_start.left() - m_partial_chunk_header)); TORRENT_ASSERT(bytes_transferred >= size_t(chunk_start.size() - m_partial_chunk_header));
bytes_transferred -= chunk_start.left() - m_partial_chunk_header; bytes_transferred -= chunk_start.size() - m_partial_chunk_header;
received_bytes(0, chunk_start.left() - m_partial_chunk_header); received_bytes(0, int(chunk_start.size() - m_partial_chunk_header));
m_partial_chunk_header = chunk_start.left(); m_partial_chunk_header = int(chunk_start.size());
if (bytes_transferred == 0) return; if (bytes_transferred == 0) return;
break; break;
} }
@ -388,7 +388,7 @@ namespace libtorrent
received_bytes(0, header_size - m_partial_chunk_header); received_bytes(0, header_size - m_partial_chunk_header);
m_partial_chunk_header = 0; m_partial_chunk_header = 0;
TORRENT_ASSERT(chunk_size != 0 || chunk_start.left() <= header_size || chunk_start.begin[header_size] == 'H'); TORRENT_ASSERT(chunk_size != 0 || chunk_start.size() <= header_size || chunk_start[header_size] == 'H');
// cut out the chunk header from the receive buffer // cut out the chunk header from the receive buffer
TORRENT_ASSERT(m_chunk_pos + m_body_start < INT_MAX); TORRENT_ASSERT(m_chunk_pos + m_body_start < INT_MAX);
m_recv_buffer.cut(header_size, t->block_size() + 1024, int(m_chunk_pos + m_body_start)); m_recv_buffer.cut(header_size, t->block_size() + 1024, int(m_chunk_pos + m_body_start));

View File

@ -214,8 +214,7 @@ void lsd::on_announce(udp::endpoint const& from, char* buf
http_parser p; http_parser p;
bool error = false; bool error = false;
p.incoming(buffer::const_interval(buf, buf + bytes_transferred) p.incoming(span<char const>(buf, bytes_transferred), error);
, error);
if (!p.header_finished() || error) if (!p.header_finished() || error)
{ {

View File

@ -51,7 +51,7 @@ boost::asio::mutable_buffer receive_buffer::reserve(int size)
{ {
int const new_size = std::max(m_recv_end + size, m_packet_size); int const new_size = std::max(m_recv_end + size, m_packet_size);
buffer new_buffer(new_size buffer new_buffer(new_size
, span<char const>(m_recv_buffer.ptr(), m_recv_end)); , span<char const>(m_recv_buffer.data(), m_recv_end));
m_recv_buffer = std::move(new_buffer); m_recv_buffer = std::move(new_buffer);
// since we just increased the size of the buffer, reset the watermark to // since we just increased the size of the buffer, reset the watermark to
@ -73,7 +73,7 @@ void receive_buffer::grow(int const limit)
// re-allcoate the buffer and copy over the part of it that's used // re-allcoate the buffer and copy over the part of it that's used
buffer new_buffer(new_size buffer new_buffer(new_size
, span<char const>(m_recv_buffer.ptr(), m_recv_end)); , span<char const>(m_recv_buffer.data(), m_recv_end));
m_recv_buffer = std::move(new_buffer); m_recv_buffer = std::move(new_buffer);
// since we just increased the size of the buffer, reset the watermark to // since we just increased the size of the buffer, reset the watermark to
@ -186,12 +186,12 @@ void receive_buffer::normalize(int force_shrink)
&& m_watermark.mean() > (m_recv_end - m_recv_start); && m_watermark.mean() > (m_recv_end - m_recv_start);
span<char const> bytes_to_shift( span<char const> bytes_to_shift(
m_recv_buffer.ptr() + m_recv_start m_recv_buffer.data() + m_recv_start
, m_recv_end - m_recv_start); , m_recv_end - m_recv_start);
if (force_shrink) if (force_shrink)
{ {
const int target_size = std::max(std::max(force_shrink int const target_size = std::max(std::max(force_shrink
, int(bytes_to_shift.size())), m_packet_size); , int(bytes_to_shift.size())), m_packet_size);
buffer new_buffer(target_size, bytes_to_shift); buffer new_buffer(target_size, bytes_to_shift);
m_recv_buffer = std::move(new_buffer); m_recv_buffer = std::move(new_buffer);
@ -204,7 +204,7 @@ void receive_buffer::normalize(int force_shrink)
else if (m_recv_end > m_recv_start else if (m_recv_end > m_recv_start
&& m_recv_start > 0) && m_recv_start > 0)
{ {
std::memmove(m_recv_buffer.ptr(), bytes_to_shift.data() std::memmove(m_recv_buffer.data(), bytes_to_shift.data()
, bytes_to_shift.size()); , bytes_to_shift.size());
} }

View File

@ -460,7 +460,7 @@ namespace libtorrent
restart_read_timeout(); restart_read_timeout();
// skip header // skip header
buf = buf.cut_first(8); buf = buf.subspan(8);
// reset transaction // reset transaction
update_transaction_id(); update_transaction_id();
@ -592,7 +592,7 @@ namespace libtorrent
{ {
if (buf.size() < 20) return false; if (buf.size() < 20) return false;
buf = buf.cut_first(8); buf = buf.subspan(8);
restart_read_timeout(); restart_read_timeout();
tracker_response resp; tracker_response resp;
@ -628,7 +628,7 @@ namespace libtorrent
{ {
ipv4_peer_entry e; ipv4_peer_entry e;
memcpy(&e.ip[0], buf.data(), 4); memcpy(&e.ip[0], buf.data(), 4);
buf = buf.cut_first(4); buf = buf.subspan(4);
e.port = aux::read_uint16(buf); e.port = aux::read_uint16(buf);
resp.peers4.push_back(e); resp.peers4.push_back(e);
} }
@ -719,9 +719,9 @@ namespace libtorrent
aux::write_int32(action_announce, out); // action (announce) aux::write_int32(action_announce, out); // action (announce)
aux::write_int32(m_transaction_id, out); // transaction_id aux::write_int32(m_transaction_id, out); // transaction_id
std::copy(req.info_hash.begin(), req.info_hash.end(), out.data()); // info_hash std::copy(req.info_hash.begin(), req.info_hash.end(), out.data()); // info_hash
out.cut_first(20); out.subspan(20);
std::copy(req.pid.begin(), req.pid.end(), out.data()); // peer_id std::copy(req.pid.begin(), req.pid.end(), out.data()); // peer_id
out.cut_first(20); out.subspan(20);
aux::write_int64(stats ? req.downloaded : 0, out); // downloaded aux::write_int64(stats ? req.downloaded : 0, out); // downloaded
aux::write_int64(stats ? req.left : 0, out); // left aux::write_int64(stats ? req.left : 0, out); // left
aux::write_int64(stats ? req.uploaded : 0, out); // uploaded aux::write_int64(stats ? req.uploaded : 0, out); // uploaded

View File

@ -435,8 +435,7 @@ void upnp::on_reply(udp::endpoint const& from, char* buffer
http_parser p; http_parser p;
bool error = false; bool error = false;
p.incoming(buffer::const_interval(buffer p.incoming(span<char const>(buffer, bytes_transferred), error);
, buffer + bytes_transferred), error);
if (error) if (error)
{ {
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING

View File

@ -655,7 +655,7 @@ void web_peer_connection::on_receive(error_code const& error
// in case the first file on this series of requests is a padfile // in case the first file on this series of requests is a padfile
// we need to handle it right now // we need to handle it right now
buffer::const_interval recv_buffer = m_recv_buffer.get(); span<char const> recv_buffer(m_recv_buffer.get().begin, m_recv_buffer.get().left());
handle_padfile(); handle_padfile();
if (associated_torrent().expired()) return; if (associated_torrent().expired()) return;
@ -669,21 +669,21 @@ void web_peer_connection::on_receive(error_code const& error
bool failed = false; bool failed = false;
std::tie(payload, protocol) = m_parser.incoming(recv_buffer, failed); std::tie(payload, protocol) = m_parser.incoming(recv_buffer, failed);
received_bytes(0, protocol); received_bytes(0, protocol);
TORRENT_ASSERT(int(recv_buffer.left()) >= protocol); TORRENT_ASSERT(int(recv_buffer.size()) >= protocol);
if (failed) if (failed)
{ {
received_bytes(0, recv_buffer.left()); received_bytes(0, int(recv_buffer.size()));
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
peer_log(peer_log_alert::info, "RECEIVE_BYTES" peer_log(peer_log_alert::info, "RECEIVE_BYTES"
, "%s", std::string(recv_buffer.begin, recv_buffer.end).c_str()); , "%s", std::string(recv_buffer.data(), recv_buffer.size()).c_str());
#endif #endif
disconnect(errors::http_parse_error, op_bittorrent, 2); disconnect(errors::http_parse_error, op_bittorrent, 2);
return; return;
} }
TORRENT_ASSERT(recv_buffer.left() == 0 || *recv_buffer.begin == 'H'); TORRENT_ASSERT(recv_buffer.empty() || recv_buffer[0] == 'H');
TORRENT_ASSERT(recv_buffer.left() <= m_recv_buffer.packet_size()); TORRENT_ASSERT(recv_buffer.size() <= m_recv_buffer.packet_size());
// this means the entire status line hasn't been received yet // this means the entire status line hasn't been received yet
if (m_parser.status_code() == -1) if (m_parser.status_code() == -1)
@ -726,26 +726,26 @@ void web_peer_connection::on_receive(error_code const& error
// if the status code is not one of the accepted ones, abort // if the status code is not one of the accepted ones, abort
if (!is_ok_status(m_parser.status_code())) if (!is_ok_status(m_parser.status_code()))
{ {
handle_error(recv_buffer.left()); handle_error(int(recv_buffer.size()));
return; return;
} }
if (is_redirect(m_parser.status_code())) if (is_redirect(m_parser.status_code()))
{ {
handle_redirect(recv_buffer.left()); handle_redirect(int(recv_buffer.size()));
return; return;
} }
m_server_string = get_peer_name(m_parser, m_host); m_server_string = get_peer_name(m_parser, m_host);
recv_buffer.begin += m_body_start; recv_buffer = recv_buffer.subspan(m_body_start);
m_body_start = m_parser.body_start(); m_body_start = m_parser.body_start();
m_received_body = 0; m_received_body = 0;
} }
// we only received the header, no data // we only received the header, no data
if (recv_buffer.left() == 0) break; if (recv_buffer.size() == 0) break;
// =================================== // ===================================
// ======= RESPONSE BYTE RANGE ======= // ======= RESPONSE BYTE RANGE =======
@ -760,7 +760,7 @@ void web_peer_connection::on_receive(error_code const& error
std::tie(range_start, range_end) = get_range(m_parser, ec); std::tie(range_start, range_end) = get_range(m_parser, ec);
if (ec) if (ec)
{ {
received_bytes(0, recv_buffer.left()); received_bytes(0, int(recv_buffer.size()));
// we should not try this server again. // we should not try this server again.
t->remove_web_seed_conn(this, ec, op_bittorrent, 2); t->remove_web_seed_conn(this, ec, op_bittorrent, 2);
m_web = nullptr; m_web = nullptr;
@ -774,7 +774,7 @@ void web_peer_connection::on_receive(error_code const& error
|| range_end != file_req.start + file_req.length) || range_end != file_req.start + file_req.length)
{ {
// the byte range in the http response is different what we expected // the byte range in the http response is different what we expected
received_bytes(0, recv_buffer.left()); received_bytes(0, int(recv_buffer.size()));
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
peer_log(peer_log_alert::incoming, "INVALID HTTP RESPONSE" peer_log(peer_log_alert::incoming, "INVALID HTTP RESPONSE"
@ -793,19 +793,19 @@ void web_peer_connection::on_receive(error_code const& error
// === CHUNKED ENCODING === // === CHUNKED ENCODING ===
// ========================= // =========================
while (m_chunk_pos >= 0 && recv_buffer.left() > 0) while (m_chunk_pos >= 0 && recv_buffer.size() > 0)
{ {
// first deliver any payload we have in the buffer so far, ahead of // first deliver any payload we have in the buffer so far, ahead of
// the next chunk header. // the next chunk header.
if (m_chunk_pos > 0) if (m_chunk_pos > 0)
{ {
int const copy_size = (std::min)(m_chunk_pos, recv_buffer.left()); int const copy_size = (std::min)(m_chunk_pos, int(recv_buffer.size()));
TORRENT_ASSERT(copy_size > 0); TORRENT_ASSERT(copy_size > 0);
if (m_received_body + copy_size > file_req.length) if (m_received_body + copy_size > file_req.length)
{ {
// the byte range in the http response is different what we expected // the byte range in the http response is different what we expected
received_bytes(0, recv_buffer.left()); received_bytes(0, int(recv_buffer.size()));
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
peer_log(peer_log_alert::incoming, "INVALID HTTP RESPONSE" peer_log(peer_log_alert::incoming, "INVALID HTTP RESPONSE"
@ -815,27 +815,26 @@ void web_peer_connection::on_receive(error_code const& error
disconnect(errors::invalid_range, op_bittorrent, 2); disconnect(errors::invalid_range, op_bittorrent, 2);
return; return;
} }
incoming_payload(recv_buffer.begin, copy_size); incoming_payload(recv_buffer.data(), copy_size);
recv_buffer.begin += copy_size; recv_buffer = recv_buffer.subspan(copy_size);
m_chunk_pos -= copy_size; m_chunk_pos -= copy_size;
if (recv_buffer.left() == 0) goto done; if (recv_buffer.size() == 0) goto done;
} }
TORRENT_ASSERT(m_chunk_pos == 0); TORRENT_ASSERT(m_chunk_pos == 0);
int header_size = 0; int header_size = 0;
std::int64_t chunk_size = 0; std::int64_t chunk_size = 0;
buffer::const_interval chunk_start = recv_buffer; span<char const> chunk_start = recv_buffer.subspan(m_chunk_pos);
chunk_start.begin += m_chunk_pos; TORRENT_ASSERT(chunk_start[0] == '\r'
TORRENT_ASSERT(chunk_start.begin[0] == '\r' || aux::is_hex(chunk_start.data(), 1));
|| aux::is_hex(chunk_start.begin, 1)); bool const ret = m_parser.parse_chunk_header(chunk_start, &chunk_size, &header_size);
bool ret = m_parser.parse_chunk_header(chunk_start, &chunk_size, &header_size);
if (!ret) if (!ret)
{ {
received_bytes(0, chunk_start.left() - m_partial_chunk_header); received_bytes(0, int(chunk_start.size() - m_partial_chunk_header));
m_partial_chunk_header = chunk_start.left(); m_partial_chunk_header = int(chunk_start.size());
goto done; goto done;
} }
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
@ -846,10 +845,10 @@ void web_peer_connection::on_receive(error_code const& error
received_bytes(0, header_size - m_partial_chunk_header); received_bytes(0, header_size - m_partial_chunk_header);
m_partial_chunk_header = 0; m_partial_chunk_header = 0;
TORRENT_ASSERT(chunk_size != 0 TORRENT_ASSERT(chunk_size != 0
|| chunk_start.left() <= header_size || chunk_start.begin[header_size] == 'H'); || chunk_start.size() <= header_size || chunk_start[header_size] == 'H');
TORRENT_ASSERT(m_body_start + m_chunk_pos < INT_MAX); TORRENT_ASSERT(m_body_start + m_chunk_pos < INT_MAX);
m_chunk_pos += chunk_size; m_chunk_pos += chunk_size;
recv_buffer.begin += header_size; recv_buffer = recv_buffer.subspan(header_size);
// a chunk size of zero means the request is complete. Make sure the // a chunk size of zero means the request is complete. Make sure the
// number of payload bytes we've received matches the number we // number of payload bytes we've received matches the number we
@ -859,9 +858,8 @@ void web_peer_connection::on_receive(error_code const& error
TORRENT_ASSERT_VAL(m_chunk_pos == 0, m_chunk_pos); TORRENT_ASSERT_VAL(m_chunk_pos == 0, m_chunk_pos);
#if TORRENT_USE_ASSERTS #if TORRENT_USE_ASSERTS
buffer::const_interval chunk = recv_buffer; span<char const> chunk = recv_buffer.subspan(m_chunk_pos);
chunk.begin += m_chunk_pos; TORRENT_ASSERT(chunk.size() == 0 || chunk[0] == 'H');
TORRENT_ASSERT(chunk.left() == 0 || chunk.begin[0] == 'H');
#endif #endif
m_chunk_pos = -1; m_chunk_pos = -1;
@ -869,7 +867,7 @@ void web_peer_connection::on_receive(error_code const& error
if (m_received_body != file_req.length) if (m_received_body != file_req.length)
{ {
// the byte range in the http response is different what we expected // the byte range in the http response is different what we expected
received_bytes(0, recv_buffer.left()); received_bytes(0, int(recv_buffer.size()));
#ifndef TORRENT_DISABLE_LOGGING #ifndef TORRENT_DISABLE_LOGGING
peer_log(peer_log_alert::incoming, "INVALID HTTP RESPONSE" peer_log(peer_log_alert::incoming, "INVALID HTTP RESPONSE"
@ -895,7 +893,7 @@ void web_peer_connection::on_receive(error_code const& error
// if all of the receive buffer was just consumed as chunk // if all of the receive buffer was just consumed as chunk
// header, we're done // header, we're done
if (recv_buffer.left() == 0) goto done; if (recv_buffer.size() == 0) goto done;
} }
} }
else else
@ -903,9 +901,9 @@ void web_peer_connection::on_receive(error_code const& error
// this is the simple case, where we don't have chunked encoding // this is the simple case, where we don't have chunked encoding
TORRENT_ASSERT(m_received_body <= file_req.length); TORRENT_ASSERT(m_received_body <= file_req.length);
int const copy_size = (std::min)(file_req.length - m_received_body int const copy_size = (std::min)(file_req.length - m_received_body
, recv_buffer.left()); , int(recv_buffer.size()));
incoming_payload(recv_buffer.begin, copy_size); incoming_payload(recv_buffer.data(), copy_size);
recv_buffer.begin += copy_size; recv_buffer = recv_buffer.subspan(copy_size);
TORRENT_ASSERT(m_received_body <= file_req.length); TORRENT_ASSERT(m_received_body <= file_req.length);
if (m_received_body == file_req.length) if (m_received_body == file_req.length)
@ -924,12 +922,12 @@ void web_peer_connection::on_receive(error_code const& error
} }
} }
if (recv_buffer.left() == 0) break; if (recv_buffer.size() == 0) break;
} }
done: done:
// now, remove all the bytes we've processed from the receive buffer // now, remove all the bytes we've processed from the receive buffer
m_recv_buffer.cut(recv_buffer.begin - m_recv_buffer.get().begin m_recv_buffer.cut(recv_buffer.data() - m_recv_buffer.get().begin
, t->block_size() + request_size_overhead); , t->block_size() + request_size_overhead);
} }

View File

@ -63,7 +63,7 @@ TORRENT_TEST(buffer_constructor)
{ {
buffer b(50, data); buffer b(50, data);
TEST_CHECK(std::memcmp(b.ptr(), data, 10) == 0); TEST_CHECK(std::memcmp(b.data(), data, 10) == 0);
TEST_CHECK(b.size() >= 50); TEST_CHECK(b.size() >= 50);
} }
} }
@ -80,13 +80,13 @@ TORRENT_TEST(buffer_swap)
TEST_CHECK(b2.size() == 0); TEST_CHECK(b2.size() == 0);
TEST_CHECK(b1.size() == b2_size); TEST_CHECK(b1.size() == b2_size);
TEST_CHECK(std::memcmp(b1.ptr(), data, 10) == 0); TEST_CHECK(std::memcmp(b1.data(), data, 10) == 0);
} }
TORRENT_TEST(buffer_subscript) TORRENT_TEST(buffer_subscript)
{ {
buffer b(50, data); buffer b(50, data);
TEST_CHECK(std::memcmp(b.ptr(), data, 10) == 0); TEST_CHECK(std::memcmp(b.data(), data, 10) == 0);
TEST_CHECK(b.size() >= 50); TEST_CHECK(b.size() >= 50);
for (int i = 0; i < int(sizeof(data)/sizeof(data[0])); ++i) for (int i = 0; i < int(sizeof(data)/sizeof(data[0])); ++i)
@ -108,21 +108,21 @@ TORRENT_TEST(buffer_subscript2)
TORRENT_TEST(buffer_move_construct) TORRENT_TEST(buffer_move_construct)
{ {
buffer b1(50, data); buffer b1(50, data);
TEST_CHECK(std::memcmp(b1.ptr(), data, 10) == 0); TEST_CHECK(std::memcmp(b1.data(), data, 10) == 0);
TEST_CHECK(b1.size() >= 50); TEST_CHECK(b1.size() >= 50);
buffer b2(std::move(b1)); buffer b2(std::move(b1));
TEST_CHECK(b1.size() == 0); TEST_CHECK(b1.size() == 0);
TEST_CHECK(std::memcmp(b2.ptr(), data, 10) == 0); TEST_CHECK(std::memcmp(b2.data(), data, 10) == 0);
TEST_CHECK(b2.size() >= 50); TEST_CHECK(b2.size() >= 50);
} }
TORRENT_TEST(buffer_move_assign) TORRENT_TEST(buffer_move_assign)
{ {
buffer b1(50, data); buffer b1(50, data);
TEST_CHECK(std::memcmp(b1.ptr(), data, 10) == 0); TEST_CHECK(std::memcmp(b1.data(), data, 10) == 0);
TEST_CHECK(b1.size() >= 50); TEST_CHECK(b1.size() >= 50);
buffer b2; buffer b2;
@ -132,7 +132,7 @@ TORRENT_TEST(buffer_move_assign)
TEST_CHECK(b1.size() == 0); TEST_CHECK(b1.size() == 0);
TEST_CHECK(std::memcmp(b2.ptr(), data, 10) == 0); TEST_CHECK(std::memcmp(b2.data(), data, 10) == 0);
TEST_CHECK(b2.size() >= 50); TEST_CHECK(b2.size() >= 50);
} }

View File

@ -38,6 +38,7 @@ POSSIBILITY OF SUCH DAMAGE.
using namespace libtorrent; using namespace libtorrent;
// TODO: 3 use span here instead of zero-terminated string
std::tuple<int, int, bool> feed_bytes(http_parser& parser, char const* str) std::tuple<int, int, bool> feed_bytes(http_parser& parser, char const* str)
{ {
std::tuple<int, int, bool> ret(0, 0, false); std::tuple<int, int, bool> ret(0, 0, false);
@ -46,12 +47,12 @@ std::tuple<int, int, bool> feed_bytes(http_parser& parser, char const* str)
{ {
ret = std::make_tuple(0, 0, false); ret = std::make_tuple(0, 0, false);
parser.reset(); parser.reset();
buffer::const_interval recv_buf(str, str); span<char const> recv_buf(str, 0);
for (; *str;) for (;;)
{ {
int chunk_size = (std::min)(chunks, int(strlen(recv_buf.end))); int chunk_size = (std::min)(chunks, int(strlen(recv_buf.end())));
if (chunk_size == 0) break; if (chunk_size == 0) break;
recv_buf.end += chunk_size; recv_buf = span<char const>(recv_buf.data(), recv_buf.size() + chunk_size);
int payload, protocol; int payload, protocol;
bool error = false; bool error = false;
std::tie(payload, protocol) = parser.incoming(recv_buf, error); std::tie(payload, protocol) = parser.incoming(recv_buf, error);
@ -332,10 +333,10 @@ TORRENT_TEST(http_parser)
char const chunk_header1[] = "f;this is a comment\r\n"; char const chunk_header1[] = "f;this is a comment\r\n";
std::int64_t chunk_size; std::int64_t chunk_size;
int header_size; int header_size;
bool ret = parser.parse_chunk_header(buffer::const_interval(chunk_header1, chunk_header1 + 10) bool ret = parser.parse_chunk_header(span<char const>(chunk_header1, 10)
, &chunk_size, &header_size); , &chunk_size, &header_size);
TEST_EQUAL(ret, false); TEST_EQUAL(ret, false);
ret = parser.parse_chunk_header(buffer::const_interval(chunk_header1, chunk_header1 + sizeof(chunk_header1)) ret = parser.parse_chunk_header(span<char const>(chunk_header1, sizeof(chunk_header1))
, &chunk_size, &header_size); , &chunk_size, &header_size);
TEST_EQUAL(ret, true); TEST_EQUAL(ret, true);
TEST_EQUAL(chunk_size, 15); TEST_EQUAL(chunk_size, 15);
@ -347,7 +348,7 @@ TORRENT_TEST(http_parser)
"test2: bar\r\n" "test2: bar\r\n"
"\r\n"; "\r\n";
ret = parser.parse_chunk_header(buffer::const_interval(chunk_header2, chunk_header2 + sizeof(chunk_header2)) ret = parser.parse_chunk_header(span<char const>(chunk_header2, sizeof(chunk_header2))
, &chunk_size, &header_size); , &chunk_size, &header_size);
TEST_EQUAL(ret, true); TEST_EQUAL(ret, true);
TEST_EQUAL(chunk_size, 0); TEST_EQUAL(chunk_size, 0);

View File

@ -73,7 +73,7 @@ void incoming_msearch(udp::endpoint const& from, char* buffer
{ {
http_parser p; http_parser p;
bool error = false; bool error = false;
p.incoming(buffer::const_interval(buffer, buffer + size), error); p.incoming(span<char const>(buffer, size), error);
if (error || !p.header_finished()) if (error || !p.header_finished())
{ {
std::cerr << "*** malformed HTTP from " std::cerr << "*** malformed HTTP from "