This source file includes following definitions.
- bytes_after_eof_
- FilterBuf
- ScanForChunkRemaining
- ParseChunkSize
#include "net/http/http_chunked_decoder.h"
#include <algorithm>
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_piece.h"
#include "base/strings/string_util.h"
#include "net/base/net_errors.h"
namespace net {
const size_t HttpChunkedDecoder::kMaxLineBufLen = 16384;
HttpChunkedDecoder::HttpChunkedDecoder()
: chunk_remaining_(0),
chunk_terminator_remaining_(false),
reached_last_chunk_(false),
reached_eof_(false),
bytes_after_eof_(0) {
}
int HttpChunkedDecoder::FilterBuf(char* buf, int buf_len) {
int result = 0;
while (buf_len) {
if (chunk_remaining_) {
int num = std::min(chunk_remaining_, buf_len);
buf_len -= num;
chunk_remaining_ -= num;
result += num;
buf += num;
if (!chunk_remaining_)
chunk_terminator_remaining_ = true;
continue;
} else if (reached_eof_) {
bytes_after_eof_ += buf_len;
break;
}
int bytes_consumed = ScanForChunkRemaining(buf, buf_len);
if (bytes_consumed < 0)
return bytes_consumed;
buf_len -= bytes_consumed;
if (buf_len)
memmove(buf, buf + bytes_consumed, buf_len);
}
return result;
}
int HttpChunkedDecoder::ScanForChunkRemaining(const char* buf, int buf_len) {
DCHECK_EQ(0, chunk_remaining_);
DCHECK_GT(buf_len, 0);
int bytes_consumed = 0;
size_t index_of_lf = base::StringPiece(buf, buf_len).find('\n');
if (index_of_lf != base::StringPiece::npos) {
buf_len = static_cast<int>(index_of_lf);
if (buf_len && buf[buf_len - 1] == '\r')
buf_len--;
bytes_consumed = static_cast<int>(index_of_lf) + 1;
if (!line_buf_.empty()) {
line_buf_.append(buf, buf_len);
buf = line_buf_.data();
buf_len = static_cast<int>(line_buf_.size());
}
if (reached_last_chunk_) {
if (buf_len)
DVLOG(1) << "ignoring http trailer";
else
reached_eof_ = true;
} else if (chunk_terminator_remaining_) {
if (buf_len) {
DLOG(ERROR) << "chunk data not terminated properly";
return ERR_INVALID_CHUNKED_ENCODING;
}
chunk_terminator_remaining_ = false;
} else if (buf_len) {
size_t index_of_semicolon = base::StringPiece(buf, buf_len).find(';');
if (index_of_semicolon != base::StringPiece::npos)
buf_len = static_cast<int>(index_of_semicolon);
if (!ParseChunkSize(buf, buf_len, &chunk_remaining_)) {
DLOG(ERROR) << "Failed parsing HEX from: " <<
std::string(buf, buf_len);
return ERR_INVALID_CHUNKED_ENCODING;
}
if (chunk_remaining_ == 0)
reached_last_chunk_ = true;
} else {
DLOG(ERROR) << "missing chunk-size";
return ERR_INVALID_CHUNKED_ENCODING;
}
line_buf_.clear();
} else {
bytes_consumed = buf_len;
if (buf[buf_len - 1] == '\r')
buf_len--;
if (line_buf_.length() + buf_len > kMaxLineBufLen) {
DLOG(ERROR) << "Chunked line length too long";
return ERR_INVALID_CHUNKED_ENCODING;
}
line_buf_.append(buf, buf_len);
}
return bytes_consumed;
}
bool HttpChunkedDecoder::ParseChunkSize(const char* start, int len, int* out) {
DCHECK_GE(len, 0);
while (len && start[len - 1] == ' ')
len--;
base::StringPiece chunk_size(start, len);
if (chunk_size.find_first_not_of("0123456789abcdefABCDEF")
!= base::StringPiece::npos) {
return false;
}
int parsed_number;
bool ok = base::HexStringToInt(chunk_size, &parsed_number);
if (ok && parsed_number >= 0) {
*out = parsed_number;
return true;
}
return false;
}
}