madf: (Default)
madf ([personal profile] madf) wrote2011-11-06 03:58 pm

Transfer-Encoding: code

Як і обіцяв, код:

void Client::_handleReadChunkLength(const boost::system::error_code & error)
{
if (!error) {
size_t length = 0;
_response.consume(parseChunkLength(_response.data(), length));
if (length == 0) {
if (!_eofCallback.empty())
_eofCallback();
_shutdown();
} else {
if (_response.size() < length + 2) {
async_read(
_socket,
_response,
transfer_at_least(length + 2 - _response.size()),
boost::bind(
&Client::_handleReadChunkData,
this,
placeholders::error,
length
)
);
} else {
_handleReadChunkData(boost::system::error_code(), length);
}
}
} else if (error == error::eof) {
if (!_eofCallback.empty())
_eofCallback();
_shutdown();
} else if (error != error::operation_aborted) {
if (!_errorCallback.empty())
_errorCallback(error);
_shutdown();
}
}

void Client::_handleReadChunkData(const boost::system::error_code & error,
size_t size)
{
if (size > 0) {
if (size > _response.size()) {
if (!_dataCallback.empty())
_dataCallback(_response.data());
} else {
if (!_dataCallback.empty())
_dataCallback(buffer(_response.data(), size));
}
}

if (!error) {
if (size > _response.size()) {
const size_t remainder = size + 2 - _response.size();
_response.consume(_response.size());
async_read(
_socket,
_response,
transfer_at_least(remainder),
boost::bind(
&Client::_handleReadChunkData,
this,
placeholders::error,
remainder - 2
)
);
} else {
_response.consume(size + 2);
async_read_until(
_socket,
_response,
"\r\n",
boost::bind(
&Client::_handleReadChunkLength,
this,
placeholders::error
)
);
}
} else if (error == error::eof) {
if (!_eofCallback.empty())
_eofCallback();
_shutdown();
} else if (error != error::operation_aborted) {
if (!_errorCallback.empty())
_errorCallback(error);
_shutdown();
}
}
_Winnie C++ Colorizer


Наведений раніше семпл містить помилку. Справа в тому що у рядку із chunk length можна крім довжини chunk вказати різні параметри після крапки з комою - так звані "chunk extensions" у вигляді key=value, розділені крапкою з комою. Якщо chunk extensions не використовуються - крапка з комою не ставляться. За стандартом ці extensions можна сміливо ігнорувати. Парсер довжини chunk наведений у семплі використовує квантор "+" для "зайвих" символів, а треба використовувати квантор "*". Ну і там ще у тому ж парсері проблеми з визначенням довжини рядка з chunk length.
Тепер щодо buffer overflow. Якщо при використанні read_until розміру буферу не вистачить для пошуку то функція завершиться з помилкою "Element not found". Наведений вище код коректно веде себе в умовах коли chunk body не влазить у бувер - оброблює його "по шматкам". Якщо ж у буфер не влазить рядок з chunk length то він завершується з помилкою "Element not found". Перевіряв це змінюючи max_size для streambuf.