2008-07-01 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>

Rewritten ChunkedEncoding class as ChunkedDecoder class.
	* src/A2STR.cc
	* src/A2STR.h
	* src/ChunkedDecoder.cc
	* src/ChunkedDecoder.h
	* src/ChunkedEncoding.cc: Removed
	* src/ChunkedEncoding.h: Removed
	* src/DownloadCommand.cc
	* src/DownloadCommand.h
	* src/HttpDownloadCommand.cc
	* src/HttpResponse.cc
	* src/HttpResponse.h
	* src/HttpResponseCommand.cc
	* src/HttpSkipResponseCommand.cc
	* src/HttpSkipResponseCommand.h
	* src/Makefile.am
	* src/TransferEncoding.h: Removed
	* test/ChunkedDecoderTest.cc
	* test/ChunkedEncodingTest.cc: Removed
	* test/HttpResponseTest.cc
	* test/Makefile.am
pull/1/head
Tatsuhiro Tsujikawa 2008-07-01 11:38:25 +00:00
parent 61bb4bc02e
commit 92c66d24ac
22 changed files with 479 additions and 492 deletions

View File

@ -1,3 +1,27 @@
2008-07-01 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
Rewritten ChunkedEncoding class as ChunkedDecoder class.
* src/A2STR.cc
* src/A2STR.h
* src/ChunkedDecoder.cc
* src/ChunkedDecoder.h
* src/ChunkedEncoding.cc: Removed
* src/ChunkedEncoding.h: Removed
* src/DownloadCommand.cc
* src/DownloadCommand.h
* src/HttpDownloadCommand.cc
* src/HttpResponse.cc
* src/HttpResponse.h
* src/HttpResponseCommand.cc
* src/HttpSkipResponseCommand.cc
* src/HttpSkipResponseCommand.h
* src/Makefile.am
* src/TransferEncoding.h: Removed
* test/ChunkedDecoderTest.cc
* test/ChunkedEncodingTest.cc: Removed
* test/HttpResponseTest.cc
* test/Makefile.am
2008-07-01 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com> 2008-07-01 Tatsuhiro Tsujikawa <tujikawa at rednoah dot com>
Use append instead of insert. Use append instead of insert.

View File

@ -52,6 +52,8 @@ const std::string A2STR::DOT_C(".");
const std::string A2STR::COLON_C(":"); const std::string A2STR::COLON_C(":");
const std::string A2STR::SEMICOLON_C(";");
const std::string A2STR::EQUAL_C("="); const std::string A2STR::EQUAL_C("=");
} // namespace aria2 } // namespace aria2

View File

@ -59,6 +59,8 @@ public:
static const std::string COLON_C; static const std::string COLON_C;
static const std::string SEMICOLON_C;
static const std::string EQUAL_C; static const std::string EQUAL_C;
}; };
} // namespace aria2 } // namespace aria2

129
src/ChunkedDecoder.cc Normal file
View File

@ -0,0 +1,129 @@
/* <!-- copyright */
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2006 Tatsuhiro Tsujikawa
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
/* copyright --> */
#include "ChunkedDecoder.h"
#include "Util.h"
#include "message.h"
#include "DlAbortEx.h"
#include "StringFormat.h"
#include "A2STR.h"
namespace aria2 {
const std::string ChunkedDecoder::NAME("ChunkedDecoder");
ChunkedDecoder::ChunkedDecoder():_chunkSize(0), _state(READ_SIZE) {}
ChunkedDecoder::~ChunkedDecoder() {}
void ChunkedDecoder::init() {}
static bool readChunkSize(size_t& chunkSize, std::string& in)
{
std::string::size_type crlfPos = in.find(A2STR::CRLF);
if(crlfPos == std::string::npos) {
return false;
}
std::string::size_type extPos = in.find(A2STR::SEMICOLON_C);
if(extPos == std::string::npos || crlfPos < extPos) {
extPos = crlfPos;
}
chunkSize = Util::parseUInt(in.substr(0, extPos), 16);
in.erase(0, crlfPos+2);
return true;
}
static bool readData(std::string& out, size_t& chunkSize, std::string& in)
{
size_t readlen = std::min(chunkSize, in.size());
out.append(in.begin(), in.begin()+readlen);
in.erase(0, readlen);
chunkSize -= readlen;
if(chunkSize == 0 && in.size() >= 2) {
if(in.find(A2STR::CRLF) == 0) {
in.erase(0, 2);
return true;
} else {
throw DlAbortEx(EX_INVALID_CHUNK_SIZE);
}
} else {
return false;
}
}
std::string ChunkedDecoder::decode(const unsigned char* inbuf, size_t inlen)
{
_buf.append(&inbuf[0], &inbuf[inlen]);
std::string outbuf;
while(1) {
if(_state == READ_SIZE) {
if(readChunkSize(_chunkSize, _buf)) {
if(_chunkSize == 0) {
_state = STREAM_END;
break;
} else {
if(_chunkSize > MAX_CHUNK_SIZE) {
throw DlAbortEx
(StringFormat(EX_TOO_LARGE_CHUNK, _chunkSize).str());
}
_state = READ_DATA;
}
} else {
break;
}
} else if(_state == READ_DATA) {
if(readData(outbuf, _chunkSize, _buf)) {
_state = READ_SIZE;
} else {
break;
}
}
}
return outbuf;
}
bool ChunkedDecoder::finished()
{
return _state == STREAM_END;
}
void ChunkedDecoder::release() {}
const std::string& ChunkedDecoder::getName() const
{
return NAME;
}
} // namespace aria2

View File

@ -32,28 +32,47 @@
* files in the program, then also delete it here. * files in the program, then also delete it here.
*/ */
/* copyright --> */ /* copyright --> */
#ifndef _D_TRANSFER_ENCODING_H_ #ifndef _D_CHUNKED_DECODER_H_
#define _D_TRANSFER_ENCODING_H_ #define _D_CHUNKED_DECODER_H_
#include "common.h" #include "Decoder.h"
#include "SharedHandle.h"
#include <stdint.h>
namespace aria2 { namespace aria2 {
class TransferEncoding { class ChunkedDecoder : public Decoder {
public: private:
virtual ~TransferEncoding() {} enum STATE {
virtual void init() = 0; READ_SIZE,
virtual void inflate(unsigned char* outbuf, size_t& outlen, READ_DATA,
const unsigned char* inbuf, size_t inlen) = 0; STREAM_END
virtual bool finished() = 0; };
virtual void end() = 0;
};
typedef SharedHandle<TransferEncoding> TransferEncodingHandle; std::string _buf;
size_t _chunkSize;
STATE _state;
static const size_t MAX_CHUNK_SIZE = 1024*1024;
static const std::string NAME;
public:
ChunkedDecoder();
virtual ~ChunkedDecoder();
virtual void init();
virtual std::string decode(const unsigned char* inbuf, size_t inlen);
virtual bool finished();
virtual void release();
virtual const std::string& getName() const;
};
} // namespace aria2 } // namespace aria2
#endif // _D_TRANSFER_ENCODING_H_ #endif // _D_DECODER_H_

View File

@ -1,194 +0,0 @@
/* <!-- copyright */
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2006 Tatsuhiro Tsujikawa
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
/* copyright --> */
#include "ChunkedEncoding.h"
#include "DlAbortEx.h"
#include "message.h"
#include "Util.h"
#include "StringFormat.h"
#include <cstring>
namespace aria2 {
#define MAX_BUFSIZE (1024*1024)
ChunkedEncoding::ChunkedEncoding() {
strbufSize = 4096;
strbuf = new unsigned char[strbufSize];
strbufTail = strbuf;
state = READ_SIZE;
chunkSize = 0;
}
ChunkedEncoding::~ChunkedEncoding() {
delete [] strbuf;
}
void ChunkedEncoding::init() {
}
bool ChunkedEncoding::finished() {
return state == FINISH ? true : false;
}
void ChunkedEncoding::end() {}
void ChunkedEncoding::inflate(unsigned char* outbuf, size_t& outlen,
const unsigned char* inbuf, size_t inlen) {
addBuffer(inbuf, inlen);
unsigned char* p = strbuf;
size_t clen = 0;
while(1) {
if(state == READ_SIZE) {
if(readChunkSize(&p) == 0) {
if(chunkSize == 0) {
state = FINISH;
} else {
state = READ_DATA;
}
} else {
// chunk size is not fully received.
break;
}
} else if(state == READ_DATA) {
if(readData(&p, outbuf, clen, outlen) == 0) {
state = READ_SIZE;
} else {
break;
}
} else {
break;
}
// all bytes in strbuf were examined?
if(strbufTail <= p) {
break;
}
}
if(strbufTail <= p) {
strbufTail = strbuf;
} else {
// copy string between [p, strbufTail]
size_t unreadSize = strbufTail-p;
unsigned char* temp = new unsigned char[strbufSize];
memcpy(temp, p, unreadSize);
delete [] strbuf;
strbuf = temp;
strbufTail = strbuf+unreadSize;
}
outlen = clen;
}
int ChunkedEncoding::readData(unsigned char** pp,
unsigned char* buf, size_t& len,
size_t maxlen)
{
if(buf+len == buf+maxlen) {
return -1;
}
if(chunkSize == 0) {
return readDataEOL(pp);
}
size_t wsize;
if((size_t)(strbufTail-*pp) < chunkSize) {
wsize = std::min((size_t)(strbufTail-*pp), maxlen-len);
} else {
wsize = std::min(chunkSize, maxlen-len);
}
memcpy(buf+len, *pp, wsize);
chunkSize -= wsize;
len += wsize;
*pp += wsize;
if(chunkSize == 0) {
return readDataEOL(pp);
} else {
return -1;
}
}
int ChunkedEncoding::readDataEOL(unsigned char** pp) {
unsigned char* np = reinterpret_cast<unsigned char*>(memchr(*pp, '\n', strbufTail-*pp));
unsigned char* rp = reinterpret_cast<unsigned char*>(memchr(*pp, '\r', strbufTail-*pp));
if(np != NULL && rp != NULL && np-rp == 1 && *pp == rp) {
*pp += 2;
return 0;
} else if(strbufTail-*pp < 2) {
return -1;
} else {
throw DlAbortEx(EX_INVALID_CHUNK_SIZE);
}
}
int ChunkedEncoding::readChunkSize(unsigned char** pp) {
// we read chunk-size from *pp
unsigned char* p;
unsigned char* np = reinterpret_cast<unsigned char*>(memchr(*pp, '\n', strbufTail-*pp));
unsigned char* rp = reinterpret_cast<unsigned char*>(memchr(*pp, '\r', strbufTail-*pp));
if(np == NULL || rp == NULL || np-rp != 1) {
// \r\n is not found. Return -1
return -1;
}
p = rp;
// We ignore chunk-extension
unsigned char* exsp = reinterpret_cast<unsigned char*>(memchr(*pp, ';', strbufTail-*pp));
if(exsp == 0 || p < exsp) {
exsp = p;
}
std::string temp(*pp, exsp);
chunkSize = Util::parseInt(temp, 16);
if(chunkSize < 0) {
throw DlAbortEx(EX_INVALID_CHUNK_SIZE);
}
*pp = p+2;
return 0;
}
void ChunkedEncoding::addBuffer(const unsigned char* inbuf, size_t inlen) {
size_t realbufSize = strbufTail-strbuf;
if(realbufSize+inlen >= strbufSize) {
if(realbufSize+inlen > MAX_BUFSIZE) {
throw DlAbortEx
(StringFormat(EX_TOO_LARGE_CHUNK, realbufSize+inlen).str());
}
strbufSize = realbufSize+inlen;
unsigned char* temp = new unsigned char[strbufSize];
memcpy(temp, strbuf, realbufSize);
delete [] strbuf;
strbuf = temp;
strbufTail = strbuf+realbufSize;
}
memcpy(strbufTail, inbuf, inlen);
strbufTail += inlen;
}
} // namespace aria2

View File

@ -1,79 +0,0 @@
/* <!-- copyright */
/*
* aria2 - The high speed download utility
*
* Copyright (C) 2006 Tatsuhiro Tsujikawa
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*
* In addition, as a special exception, the copyright holders give
* permission to link the code of portions of this program with the
* OpenSSL library under certain conditions as described in each
* individual source file, and distribute linked combinations
* including the two.
* You must obey the GNU General Public License in all respects
* for all of the code used other than OpenSSL. If you modify
* file(s) with this exception, you may extend this exception to your
* version of the file(s), but you are not obligated to do so. If you
* do not wish to do so, delete this exception statement from your
* version. If you delete this exception statement from all source
* files in the program, then also delete it here.
*/
/* copyright --> */
#ifndef _D_CHUNKED_ENCODING_H_
#define _D_CHUNKED_ENCODING_H_
#include "TransferEncoding.h"
namespace aria2 {
class ChunkedEncoding:public TransferEncoding {
private:
enum STATE {
READ_SIZE,
READ_DATA,
FINISH
};
size_t chunkSize;
STATE state;
unsigned char* strbuf;
size_t strbufSize;
unsigned char* strbufTail;
/**
* Returns 0 if the size of chunk is retrieved successfully,
* otherwise returns non-zero value.
*/
int readChunkSize(unsigned char** pp);
int readData(unsigned char** pp, unsigned char* buf, size_t& len,
size_t maxlen);
void addBuffer(const unsigned char* inbuf, size_t inlen);
int readDataEOL(unsigned char** pp);
public:
ChunkedEncoding();
~ChunkedEncoding();
void init();
void inflate(unsigned char* outbuf, size_t& outlen,
const unsigned char* inbuf, size_t inlen);
bool finished();
void end();
};
} // namespace aria2
#endif // _D_CHUNKED_ENCODING_H_

View File

@ -123,19 +123,18 @@ bool DownloadCommand::executeInternal() {
const SharedHandle<DiskAdaptor>& diskAdaptor = const SharedHandle<DiskAdaptor>& diskAdaptor =
_requestGroup->getPieceStorage()->getDiskAdaptor(); _requestGroup->getPieceStorage()->getDiskAdaptor();
unsigned char* bufFinal; const unsigned char* bufFinal;
size_t bufSizeFinal; size_t bufSizeFinal;
if(transferDecoder.isNull()) { std::string decoded;
if(_transferEncodingDecoder.isNull()) {
bufFinal = buf; bufFinal = buf;
bufSizeFinal = bufSize; bufSizeFinal = bufSize;
} else { } else {
size_t infbufSize = 16*1024; decoded = _transferEncodingDecoder->decode(buf, bufSize);
unsigned char infbuf[infbufSize];
transferDecoder->inflate(infbuf, infbufSize, buf, bufSize);
bufFinal = infbuf; bufFinal = reinterpret_cast<const unsigned char*>(decoded.c_str());
bufSizeFinal = infbufSize; bufSizeFinal = decoded.size();
} }
if(_contentEncodingDecoder.isNull()) { if(_contentEncodingDecoder.isNull()) {
@ -164,10 +163,10 @@ bool DownloadCommand::executeInternal() {
if(_requestGroup->getTotalLength() != 0 && bufSize == 0) { if(_requestGroup->getTotalLength() != 0 && bufSize == 0) {
throw DlRetryEx(EX_GOT_EOF); throw DlRetryEx(EX_GOT_EOF);
} }
if((!transferDecoder.isNull() && transferDecoder->finished()) if((!_transferEncodingDecoder.isNull() &&
|| (transferDecoder.isNull() && segment->complete()) _transferEncodingDecoder->finished())
|| (_transferEncodingDecoder.isNull() && segment->complete())
|| bufSize == 0) { || bufSize == 0) {
if(!transferDecoder.isNull()) transferDecoder->end();
logger->info(MSG_SEGMENT_DOWNLOAD_COMPLETED, cuid); logger->info(MSG_SEGMENT_DOWNLOAD_COMPLETED, cuid);
if(!_contentEncodingDecoder.isNull() && if(!_contentEncodingDecoder.isNull() &&
@ -284,9 +283,10 @@ void DownloadCommand::validatePieceHash(const SharedHandle<Segment>& segment,
#endif // ENABLE_MESSAGE_DIGEST #endif // ENABLE_MESSAGE_DIGEST
void DownloadCommand::setTransferDecoder(const TransferEncodingHandle& transferDecoder) void DownloadCommand::setTransferEncodingDecoder
(const SharedHandle<Decoder>& decoder)
{ {
this->transferDecoder = transferDecoder; this->_transferEncodingDecoder = decoder;
} }
void DownloadCommand::setContentEncodingDecoder void DownloadCommand::setContentEncodingDecoder

View File

@ -67,7 +67,7 @@ private:
void checkLowestDownloadSpeed() const; void checkLowestDownloadSpeed() const;
protected: protected:
SharedHandle<TransferEncoding> transferDecoder; SharedHandle<Decoder> _transferEncodingDecoder;
SharedHandle<Decoder> _contentEncodingDecoder; SharedHandle<Decoder> _contentEncodingDecoder;
@ -83,7 +83,7 @@ public:
const SharedHandle<SocketCore>& s); const SharedHandle<SocketCore>& s);
virtual ~DownloadCommand(); virtual ~DownloadCommand();
void setTransferDecoder(const SharedHandle<TransferEncoding>& transferDecoder); void setTransferEncodingDecoder(const SharedHandle<Decoder>& decoder);
void setContentEncodingDecoder(const SharedHandle<Decoder>& decoder); void setContentEncodingDecoder(const SharedHandle<Decoder>& decoder);

View File

@ -66,8 +66,10 @@ bool HttpDownloadCommand::prepareForNextSegment() {
if(!e->option->getAsBool(PREF_HTTP_PROXY_ENABLED)) { if(!e->option->getAsBool(PREF_HTTP_PROXY_ENABLED)) {
if(req->isPipeliningEnabled() || if(req->isPipeliningEnabled() ||
(req->isKeepAliveEnabled() && (req->isKeepAliveEnabled() &&
((!transferDecoder.isNull() && _requestGroup->downloadFinished()) || ((!_transferEncodingDecoder.isNull() &&
(uint64_t)_segments.front()->getPositionToWrite() == _requestGroup->getTotalLength()))) { _requestGroup->downloadFinished()) ||
(uint64_t)_segments.front()->getPositionToWrite() ==
_requestGroup->getTotalLength()))) {
std::pair<std::string, uint16_t> peerInfo; std::pair<std::string, uint16_t> peerInfo;
socket->getPeerInfo(peerInfo); socket->getPeerInfo(peerInfo);
e->poolSocket(peerInfo.first, peerInfo.second, socket); e->poolSocket(peerInfo.first, peerInfo.second, socket);

View File

@ -41,13 +41,13 @@
#include "Range.h" #include "Range.h"
#include "LogFactory.h" #include "LogFactory.h"
#include "Logger.h" #include "Logger.h"
#include "ChunkedEncoding.h"
#include "Util.h" #include "Util.h"
#include "message.h" #include "message.h"
#include "DlAbortEx.h" #include "DlAbortEx.h"
#include "StringFormat.h" #include "StringFormat.h"
#include "A2STR.h" #include "A2STR.h"
#include "Decoder.h" #include "Decoder.h"
#include "ChunkedDecoder.h"
#ifdef HAVE_LIBZ #ifdef HAVE_LIBZ
# include "GZipDecoder.h" # include "GZipDecoder.h"
#endif // HAVE_LIBZ #endif // HAVE_LIBZ
@ -73,21 +73,19 @@ void HttpResponse::validateResponse() const
(StringFormat(EX_LOCATION_HEADER_REQUIRED, (StringFormat(EX_LOCATION_HEADER_REQUIRED,
Util::parseUInt(status)).str()); Util::parseUInt(status)).str());
} }
} else { } else if(!httpHeader->defined(HttpHeader::TRANSFER_ENCODING)) {
if(!httpHeader->defined(HttpHeader::TRANSFER_ENCODING)) { // compare the received range against the requested range
// compare the received range against the requested range RangeHandle responseRange = httpHeader->getRange();
RangeHandle responseRange = httpHeader->getRange(); if(!httpRequest->isRangeSatisfied(responseRange)) {
if(!httpRequest->isRangeSatisfied(responseRange)) { throw DlAbortEx
throw DlAbortEx (StringFormat
(StringFormat(EX_INVALID_RANGE_HEADER, (EX_INVALID_RANGE_HEADER,
Util::itos(httpRequest->getStartByte(), true).c_str(), Util::itos(httpRequest->getStartByte(), true).c_str(),
Util::itos(httpRequest->getEndByte(), true).c_str(), Util::itos(httpRequest->getEndByte(), true).c_str(),
Util::uitos(httpRequest->getEntityLength(), true).c_str(), Util::uitos(httpRequest->getEntityLength(), true).c_str(),
Util::itos(responseRange->getStartByte(), true).c_str(), Util::itos(responseRange->getStartByte(), true).c_str(),
Util::itos(responseRange->getEndByte(), true).c_str(), Util::itos(responseRange->getEndByte(), true).c_str(),
Util::uitos(responseRange->getEntityLength(), true).c_str() Util::uitos(responseRange->getEntityLength(), true).c_str()).str());
).str());
}
} }
} }
} }
@ -109,10 +107,10 @@ std::string HttpResponse::determinFilename() const
void HttpResponse::retrieveCookie() void HttpResponse::retrieveCookie()
{ {
std::deque<std::string> v = httpHeader->get(HttpHeader::SET_COOKIE); std::deque<std::string> v = httpHeader->get(HttpHeader::SET_COOKIE);
for(std::deque<std::string>::const_iterator itr = v.begin(); itr != v.end(); itr++) { for(std::deque<std::string>::const_iterator itr = v.begin(); itr != v.end();
std::string domain = httpRequest->getHost(); itr++) {
std::string path = httpRequest->getDir(); httpRequest->getRequest()->cookieBox->add(*itr, httpRequest->getHost(),
httpRequest->getRequest()->cookieBox->add(*itr, domain, path); httpRequest->getDir());
} }
} }
@ -141,17 +139,20 @@ bool HttpResponse::isTransferEncodingSpecified() const
std::string HttpResponse::getTransferEncoding() const std::string HttpResponse::getTransferEncoding() const
{ {
// TODO See TODO in getTransferEncodingDecoder()
return httpHeader->getFirst(HttpHeader::TRANSFER_ENCODING); return httpHeader->getFirst(HttpHeader::TRANSFER_ENCODING);
} }
TransferEncodingHandle HttpResponse::getTransferDecoder() const SharedHandle<Decoder> HttpResponse::getTransferEncodingDecoder() const
{ {
// TODO Transfer-Encoding header field can contains multiple tokens. We should
// parse the field and retrieve each token.
if(isTransferEncodingSpecified()) { if(isTransferEncodingSpecified()) {
if(getTransferEncoding() == HttpHeader::CHUNKED) { if(getTransferEncoding() == HttpHeader::CHUNKED) {
return SharedHandle<TransferEncoding>(new ChunkedEncoding()); return SharedHandle<Decoder>(new ChunkedDecoder());
} }
} }
return SharedHandle<TransferEncoding>(); return SharedHandle<Decoder>();
} }
bool HttpResponse::isContentEncodingSpecified() const bool HttpResponse::isContentEncodingSpecified() const

View File

@ -44,7 +44,6 @@ namespace aria2 {
class HttpRequest; class HttpRequest;
class HttpHeader; class HttpHeader;
class TransferEncoding;
class Logger; class Logger;
class Decoder; class Decoder;
@ -84,7 +83,7 @@ public:
std::string getTransferEncoding() const; std::string getTransferEncoding() const;
SharedHandle<TransferEncoding> getTransferDecoder() const; SharedHandle<Decoder> getTransferEncodingDecoder() const;
bool isContentEncodingSpecified() const; bool isContentEncodingSpecified() const;

View File

@ -180,20 +180,20 @@ bool HttpResponseCommand::handleOtherEncoding(const HttpResponseHandle& httpResp
return true; return true;
} }
static SharedHandle<TransferEncoding> getTransferEncoding static SharedHandle<Decoder> getTransferEncodingDecoder
(const SharedHandle<HttpResponse>& httpResponse) (const SharedHandle<HttpResponse>& httpResponse)
{ {
TransferEncodingHandle enc; SharedHandle<Decoder> decoder;
if(httpResponse->isTransferEncodingSpecified()) { if(httpResponse->isTransferEncodingSpecified()) {
enc = httpResponse->getTransferDecoder(); decoder = httpResponse->getTransferEncodingDecoder();
if(enc.isNull()) { if(decoder.isNull()) {
throw DlAbortEx throw DlAbortEx
(StringFormat(EX_TRANSFER_ENCODING_NOT_SUPPORTED, (StringFormat(EX_TRANSFER_ENCODING_NOT_SUPPORTED,
httpResponse->getTransferEncoding().c_str()).str()); httpResponse->getTransferEncoding().c_str()).str());
} }
enc->init(); decoder->init();
} }
return enc; return decoder;
} }
static SharedHandle<Decoder> getContentEncodingDecoder static SharedHandle<Decoder> getContentEncodingDecoder
@ -218,13 +218,13 @@ static SharedHandle<Decoder> getContentEncodingDecoder
bool HttpResponseCommand::skipResponseBody bool HttpResponseCommand::skipResponseBody
(const SharedHandle<HttpResponse>& httpResponse) (const SharedHandle<HttpResponse>& httpResponse)
{ {
SharedHandle<TransferEncoding> enc(getTransferEncoding(httpResponse)); SharedHandle<Decoder> decoder = getTransferEncodingDecoder(httpResponse);
// We don't use Content-Encoding here because this response body is just // We don't use Content-Encoding here because this response body is just
// thrown away. // thrown away.
HttpSkipResponseCommand* command = new HttpSkipResponseCommand HttpSkipResponseCommand* command = new HttpSkipResponseCommand
(cuid, req, _requestGroup, httpConnection, httpResponse, e, socket); (cuid, req, _requestGroup, httpConnection, httpResponse, e, socket);
command->setTransferDecoder(enc); command->setTransferEncodingDecoder(decoder);
// If the response body is zero-length, set command's status to real time // If the response body is zero-length, set command's status to real time
// so that avoid read check blocking // so that avoid read check blocking
@ -238,18 +238,23 @@ bool HttpResponseCommand::skipResponseBody
return true; return true;
} }
HttpDownloadCommand* HttpResponseCommand::createHttpDownloadCommand(const HttpResponseHandle& httpResponse) HttpDownloadCommand* HttpResponseCommand::createHttpDownloadCommand
(const HttpResponseHandle& httpResponse)
{ {
TransferEncodingHandle enc = getTransferEncoding(httpResponse); SharedHandle<Decoder> transferEncodingDecoder =
getTransferEncodingDecoder(httpResponse);
SharedHandle<Decoder> contentEncodingDecoder = SharedHandle<Decoder> contentEncodingDecoder =
getContentEncodingDecoder(httpResponse); getContentEncodingDecoder(httpResponse);
HttpDownloadCommand* command = HttpDownloadCommand* command =
new HttpDownloadCommand(cuid, req, _requestGroup, httpConnection, e, socket); new HttpDownloadCommand(cuid, req, _requestGroup, httpConnection, e,
command->setMaxDownloadSpeedLimit(e->option->getAsInt(PREF_MAX_DOWNLOAD_LIMIT)); socket);
command->setMaxDownloadSpeedLimit
(e->option->getAsInt(PREF_MAX_DOWNLOAD_LIMIT));
command->setStartupIdleTime(e->option->getAsInt(PREF_STARTUP_IDLE_TIME)); command->setStartupIdleTime(e->option->getAsInt(PREF_STARTUP_IDLE_TIME));
command->setLowestDownloadSpeedLimit(e->option->getAsInt(PREF_LOWEST_SPEED_LIMIT)); command->setLowestDownloadSpeedLimit
command->setTransferDecoder(enc); (e->option->getAsInt(PREF_LOWEST_SPEED_LIMIT));
command->setTransferEncodingDecoder(transferEncodingDecoder);
if(!contentEncodingDecoder.isNull()) { if(!contentEncodingDecoder.isNull()) {
command->setContentEncodingDecoder(contentEncodingDecoder); command->setContentEncodingDecoder(contentEncodingDecoder);

View File

@ -37,7 +37,7 @@
#include "HttpResponse.h" #include "HttpResponse.h"
#include "message.h" #include "message.h"
#include "SocketCore.h" #include "SocketCore.h"
#include "TransferEncoding.h" #include "Decoder.h"
#include "DlRetryEx.h" #include "DlRetryEx.h"
#include "Request.h" #include "Request.h"
#include "DownloadEngine.h" #include "DownloadEngine.h"
@ -70,15 +70,15 @@ HttpSkipResponseCommand::HttpSkipResponseCommand
HttpSkipResponseCommand::~HttpSkipResponseCommand() {} HttpSkipResponseCommand::~HttpSkipResponseCommand() {}
void HttpSkipResponseCommand::setTransferDecoder void HttpSkipResponseCommand::setTransferEncodingDecoder
(const SharedHandle<TransferEncoding>& transferDecoder) (const SharedHandle<Decoder>& decoder)
{ {
_transferDecoder = transferDecoder; _transferEncodingDecoder = decoder;
} }
bool HttpSkipResponseCommand::executeInternal() bool HttpSkipResponseCommand::executeInternal()
{ {
if(_totalLength == 0 && _transferDecoder.isNull()) { if(_totalLength == 0 && _transferEncodingDecoder.isNull()) {
return processResponse(); return processResponse();
} }
const size_t BUFSIZE = 16*1024; const size_t BUFSIZE = 16*1024;
@ -88,13 +88,12 @@ bool HttpSkipResponseCommand::executeInternal()
try { try {
socket->readData(buf, bufSize); socket->readData(buf, bufSize);
if(_transferDecoder.isNull()) { if(_transferEncodingDecoder.isNull()) {
_receivedBytes += bufSize; _receivedBytes += bufSize;
} else { } else {
// _receivedBytes is not updated if transferEncoding is set. // _receivedBytes is not updated if transferEncoding is set.
size_t infbufSize = 16*1024; // The return value is safely ignored here.
unsigned char infbuf[infbufSize]; _transferEncodingDecoder->decode(buf, bufSize);
_transferDecoder->inflate(infbuf, infbufSize, buf, bufSize);
} }
if(_totalLength != 0 && bufSize == 0) { if(_totalLength != 0 && bufSize == 0) {
throw DlRetryEx(EX_GOT_EOF); throw DlRetryEx(EX_GOT_EOF);
@ -109,10 +108,10 @@ bool HttpSkipResponseCommand::executeInternal()
// readable, bufSize == 0 means server shutdown the connection. // readable, bufSize == 0 means server shutdown the connection.
// So socket cannot be reused in this case. // So socket cannot be reused in this case.
return prepareForRetry(0); return prepareForRetry(0);
} else if((!_transferDecoder.isNull() && _transferDecoder->finished()) } else if((!_transferEncodingDecoder.isNull() &&
|| (_transferDecoder.isNull() && _totalLength == _receivedBytes)) { _transferEncodingDecoder->finished())
if(!_transferDecoder.isNull()) _transferDecoder->end(); || (_transferEncodingDecoder.isNull() &&
_totalLength == _receivedBytes)) {
if(!e->option->getAsBool(PREF_HTTP_PROXY_ENABLED) && if(!e->option->getAsBool(PREF_HTTP_PROXY_ENABLED) &&
req->supportsPersistentConnection()) { req->supportsPersistentConnection()) {
std::pair<std::string, uint16_t> peerInfo; std::pair<std::string, uint16_t> peerInfo;

View File

@ -41,7 +41,7 @@ namespace aria2 {
class HttpConnection; class HttpConnection;
class HttpResponse; class HttpResponse;
class TransferEncoding; class Decoder;
class HttpSkipResponseCommand : public AbstractCommand { class HttpSkipResponseCommand : public AbstractCommand {
private: private:
@ -49,7 +49,7 @@ private:
SharedHandle<HttpResponse> _httpResponse; SharedHandle<HttpResponse> _httpResponse;
SharedHandle<TransferEncoding> _transferDecoder; SharedHandle<Decoder> _transferEncodingDecoder;
uint64_t _totalLength; uint64_t _totalLength;
@ -69,7 +69,7 @@ public:
virtual ~HttpSkipResponseCommand(); virtual ~HttpSkipResponseCommand();
void setTransferDecoder(const SharedHandle<TransferEncoding>& transferDecoder); void setTransferEncodingDecoder(const SharedHandle<Decoder>& decoder);
}; };
} // namespace aria2 } // namespace aria2

View File

@ -41,8 +41,6 @@ SRCS = Socket.h\
DownloadFailureException.h\ DownloadFailureException.h\
Logger.h\ Logger.h\
SimpleLogger.cc SimpleLogger.h\ SimpleLogger.cc SimpleLogger.h\
TransferEncoding.h\
ChunkedEncoding.cc ChunkedEncoding.h\
DiskWriter.h\ DiskWriter.h\
DiskWriterFactory.h\ DiskWriterFactory.h\
AbstractDiskWriter.cc AbstractDiskWriter.h\ AbstractDiskWriter.cc AbstractDiskWriter.h\
@ -189,7 +187,8 @@ SRCS = Socket.h\
FtpFinishDownloadCommand.cc FtpFinishDownloadCommand.h\ FtpFinishDownloadCommand.cc FtpFinishDownloadCommand.h\
A2STR.cc A2STR.h\ A2STR.cc A2STR.h\
RarestPieceSelector.cc RarestPieceSelector.h\ RarestPieceSelector.cc RarestPieceSelector.h\
Decoder.h Decoder.h\
ChunkedDecoder.cc ChunkedDecoder.h
if HAVE_LIBZ if HAVE_LIBZ
SRCS += GZipDecoder.cc GZipDecoder.h SRCS += GZipDecoder.cc GZipDecoder.h

View File

@ -317,8 +317,7 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
message.h Exception.cc Exception.h FatalException.h \ message.h Exception.cc Exception.h FatalException.h \
RecoverableException.h DlAbortEx.h DlRetryEx.h \ RecoverableException.h DlAbortEx.h DlRetryEx.h \
DownloadFailureException.h Logger.h SimpleLogger.cc \ DownloadFailureException.h Logger.h SimpleLogger.cc \
SimpleLogger.h TransferEncoding.h ChunkedEncoding.cc \ SimpleLogger.h DiskWriter.h DiskWriterFactory.h \
ChunkedEncoding.h DiskWriter.h DiskWriterFactory.h \
AbstractDiskWriter.cc AbstractDiskWriter.h \ AbstractDiskWriter.cc AbstractDiskWriter.h \
DefaultDiskWriter.cc DefaultDiskWriter.h \ DefaultDiskWriter.cc DefaultDiskWriter.h \
DefaultDiskWriterFactory.cc DefaultDiskWriterFactory.h File.cc \ DefaultDiskWriterFactory.cc DefaultDiskWriterFactory.h File.cc \
@ -407,8 +406,9 @@ am__libaria2c_a_SOURCES_DIST = Socket.h SocketCore.cc SocketCore.h \
InitiateConnectionCommand.cc InitiateConnectionCommand.h \ InitiateConnectionCommand.cc InitiateConnectionCommand.h \
FtpFinishDownloadCommand.cc FtpFinishDownloadCommand.h \ FtpFinishDownloadCommand.cc FtpFinishDownloadCommand.h \
A2STR.cc A2STR.h RarestPieceSelector.cc RarestPieceSelector.h \ A2STR.cc A2STR.h RarestPieceSelector.cc RarestPieceSelector.h \
Decoder.h GZipDecoder.cc GZipDecoder.h AsyncNameResolver.cc \ Decoder.h ChunkedDecoder.cc ChunkedDecoder.h GZipDecoder.cc \
AsyncNameResolver.h IteratableChunkChecksumValidator.cc \ GZipDecoder.h AsyncNameResolver.cc AsyncNameResolver.h \
IteratableChunkChecksumValidator.cc \
IteratableChunkChecksumValidator.h \ IteratableChunkChecksumValidator.h \
IteratableChecksumValidator.cc IteratableChecksumValidator.h \ IteratableChecksumValidator.cc IteratableChecksumValidator.h \
CheckIntegrityCommand.cc CheckIntegrityCommand.h \ CheckIntegrityCommand.cc CheckIntegrityCommand.h \
@ -740,15 +740,14 @@ am__objects_17 = SocketCore.$(OBJEXT) Command.$(OBJEXT) \
DownloadEngine.$(OBJEXT) GrowSegment.$(OBJEXT) \ DownloadEngine.$(OBJEXT) GrowSegment.$(OBJEXT) \
PiecedSegment.$(OBJEXT) SegmentMan.$(OBJEXT) Util.$(OBJEXT) \ PiecedSegment.$(OBJEXT) SegmentMan.$(OBJEXT) Util.$(OBJEXT) \
Request.$(OBJEXT) Exception.$(OBJEXT) SimpleLogger.$(OBJEXT) \ Request.$(OBJEXT) Exception.$(OBJEXT) SimpleLogger.$(OBJEXT) \
ChunkedEncoding.$(OBJEXT) AbstractDiskWriter.$(OBJEXT) \ AbstractDiskWriter.$(OBJEXT) DefaultDiskWriter.$(OBJEXT) \
DefaultDiskWriter.$(OBJEXT) DefaultDiskWriterFactory.$(OBJEXT) \ DefaultDiskWriterFactory.$(OBJEXT) File.$(OBJEXT) \
File.$(OBJEXT) Option.$(OBJEXT) Base64.$(OBJEXT) \ Option.$(OBJEXT) Base64.$(OBJEXT) CookieBox.$(OBJEXT) \
CookieBox.$(OBJEXT) LogFactory.$(OBJEXT) TimeA2.$(OBJEXT) \ LogFactory.$(OBJEXT) TimeA2.$(OBJEXT) FeatureConfig.$(OBJEXT) \
FeatureConfig.$(OBJEXT) DownloadEngineFactory.$(OBJEXT) \ DownloadEngineFactory.$(OBJEXT) SpeedCalc.$(OBJEXT) \
SpeedCalc.$(OBJEXT) BitfieldMan.$(OBJEXT) \ BitfieldMan.$(OBJEXT) BitfieldManFactory.$(OBJEXT) \
BitfieldManFactory.$(OBJEXT) SimpleRandomizer.$(OBJEXT) \ SimpleRandomizer.$(OBJEXT) HttpResponse.$(OBJEXT) \
HttpResponse.$(OBJEXT) HttpRequest.$(OBJEXT) \ HttpRequest.$(OBJEXT) AbstractProxyRequestCommand.$(OBJEXT) \
AbstractProxyRequestCommand.$(OBJEXT) \
AbstractProxyResponseCommand.$(OBJEXT) Netrc.$(OBJEXT) \ AbstractProxyResponseCommand.$(OBJEXT) Netrc.$(OBJEXT) \
AuthConfig.$(OBJEXT) AbstractAuthResolver.$(OBJEXT) \ AuthConfig.$(OBJEXT) AbstractAuthResolver.$(OBJEXT) \
DefaultAuthResolver.$(OBJEXT) NetrcAuthResolver.$(OBJEXT) \ DefaultAuthResolver.$(OBJEXT) NetrcAuthResolver.$(OBJEXT) \
@ -794,12 +793,13 @@ am__objects_17 = SocketCore.$(OBJEXT) Command.$(OBJEXT) \
HttpSkipResponseCommand.$(OBJEXT) \ HttpSkipResponseCommand.$(OBJEXT) \
InitiateConnectionCommand.$(OBJEXT) \ InitiateConnectionCommand.$(OBJEXT) \
FtpFinishDownloadCommand.$(OBJEXT) A2STR.$(OBJEXT) \ FtpFinishDownloadCommand.$(OBJEXT) A2STR.$(OBJEXT) \
RarestPieceSelector.$(OBJEXT) $(am__objects_1) \ RarestPieceSelector.$(OBJEXT) ChunkedDecoder.$(OBJEXT) \
$(am__objects_2) $(am__objects_3) $(am__objects_4) \ $(am__objects_1) $(am__objects_2) $(am__objects_3) \
$(am__objects_5) $(am__objects_6) $(am__objects_7) \ $(am__objects_4) $(am__objects_5) $(am__objects_6) \
$(am__objects_8) $(am__objects_9) $(am__objects_10) \ $(am__objects_7) $(am__objects_8) $(am__objects_9) \
$(am__objects_11) $(am__objects_12) $(am__objects_13) \ $(am__objects_10) $(am__objects_11) $(am__objects_12) \
$(am__objects_14) $(am__objects_15) $(am__objects_16) $(am__objects_13) $(am__objects_14) $(am__objects_15) \
$(am__objects_16)
am_libaria2c_a_OBJECTS = $(am__objects_17) am_libaria2c_a_OBJECTS = $(am__objects_17)
libaria2c_a_OBJECTS = $(am_libaria2c_a_OBJECTS) libaria2c_a_OBJECTS = $(am_libaria2c_a_OBJECTS)
am__installdirs = "$(DESTDIR)$(bindir)" am__installdirs = "$(DESTDIR)$(bindir)"
@ -1027,8 +1027,7 @@ SRCS = Socket.h SocketCore.cc SocketCore.h BinaryStream.h Command.cc \
message.h Exception.cc Exception.h FatalException.h \ message.h Exception.cc Exception.h FatalException.h \
RecoverableException.h DlAbortEx.h DlRetryEx.h \ RecoverableException.h DlAbortEx.h DlRetryEx.h \
DownloadFailureException.h Logger.h SimpleLogger.cc \ DownloadFailureException.h Logger.h SimpleLogger.cc \
SimpleLogger.h TransferEncoding.h ChunkedEncoding.cc \ SimpleLogger.h DiskWriter.h DiskWriterFactory.h \
ChunkedEncoding.h DiskWriter.h DiskWriterFactory.h \
AbstractDiskWriter.cc AbstractDiskWriter.h \ AbstractDiskWriter.cc AbstractDiskWriter.h \
DefaultDiskWriter.cc DefaultDiskWriter.h \ DefaultDiskWriter.cc DefaultDiskWriter.h \
DefaultDiskWriterFactory.cc DefaultDiskWriterFactory.h File.cc \ DefaultDiskWriterFactory.cc DefaultDiskWriterFactory.h File.cc \
@ -1117,12 +1116,12 @@ SRCS = Socket.h SocketCore.cc SocketCore.h BinaryStream.h Command.cc \
InitiateConnectionCommand.cc InitiateConnectionCommand.h \ InitiateConnectionCommand.cc InitiateConnectionCommand.h \
FtpFinishDownloadCommand.cc FtpFinishDownloadCommand.h \ FtpFinishDownloadCommand.cc FtpFinishDownloadCommand.h \
A2STR.cc A2STR.h RarestPieceSelector.cc RarestPieceSelector.h \ A2STR.cc A2STR.h RarestPieceSelector.cc RarestPieceSelector.h \
Decoder.h $(am__append_1) $(am__append_2) $(am__append_3) \ Decoder.h ChunkedDecoder.cc ChunkedDecoder.h $(am__append_1) \
$(am__append_4) $(am__append_5) $(am__append_6) \ $(am__append_2) $(am__append_3) $(am__append_4) \
$(am__append_7) $(am__append_8) $(am__append_9) \ $(am__append_5) $(am__append_6) $(am__append_7) \
$(am__append_10) $(am__append_11) $(am__append_12) \ $(am__append_8) $(am__append_9) $(am__append_10) \
$(am__append_13) $(am__append_14) $(am__append_15) \ $(am__append_11) $(am__append_12) $(am__append_13) \
$(am__append_16) $(am__append_14) $(am__append_15) $(am__append_16)
noinst_LIBRARIES = libaria2c.a noinst_LIBRARIES = libaria2c.a
libaria2c_a_SOURCES = $(SRCS) libaria2c_a_SOURCES = $(SRCS)
aria2c_LDADD = libaria2c.a @LIBINTL@ @ALLOCA@ @LIBGNUTLS_LIBS@\ aria2c_LDADD = libaria2c.a @LIBINTL@ @ALLOCA@ @LIBGNUTLS_LIBS@\
@ -1264,7 +1263,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CheckIntegrityEntry.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CheckIntegrityEntry.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CheckIntegrityMan.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CheckIntegrityMan.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ChecksumCheckIntegrityEntry.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ChecksumCheckIntegrityEntry.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ChunkedEncoding.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ChunkedDecoder.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Command.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/Command.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CompactPeerListProcessor.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CompactPeerListProcessor.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ConsoleStatCalc.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ConsoleStatCalc.Po@am__quote@

146
test/ChunkedDecoderTest.cc Normal file
View File

@ -0,0 +1,146 @@
#include "ChunkedDecoder.h"
#include "DlAbortEx.h"
#include <iostream>
#include <cppunit/extensions/HelperMacros.h>
namespace aria2 {
class ChunkedDecoderTest:public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(ChunkedDecoderTest);
CPPUNIT_TEST(testDecode);
CPPUNIT_TEST(testDecode_tooLargeChunkSize);
CPPUNIT_TEST(testDecode_chunkSizeMismatch);
CPPUNIT_TEST(testGetName);
CPPUNIT_TEST_SUITE_END();
public:
void setUp() {}
void testDecode();
void testDecode_tooLargeChunkSize();
void testDecode_chunkSizeMismatch();
void testGetName();
};
CPPUNIT_TEST_SUITE_REGISTRATION( ChunkedDecoderTest );
void ChunkedDecoderTest::testDecode()
{
ChunkedDecoder decoder;
decoder.init();
{
std::basic_string<unsigned char> msg =
reinterpret_cast<const unsigned char*>("a\r\n1234567890\r\n");
CPPUNIT_ASSERT_EQUAL(std::string("1234567890"),
decoder.decode(msg.c_str(), msg.size()));
}
// Feed extension; see it is ignored.
{
std::basic_string<unsigned char> msg =
reinterpret_cast<const unsigned char*>
("3;extensionIgnored\r\n123\r\n");
CPPUNIT_ASSERT_EQUAL(std::string("123"),
decoder.decode(msg.c_str(), msg.size()));
}
// Not all chunk size is available
{
std::basic_string<unsigned char> msg =
reinterpret_cast<const unsigned char*>("1");
CPPUNIT_ASSERT_EQUAL(std::string(),
decoder.decode(msg.c_str(), msg.size()));
}
{
std::basic_string<unsigned char> msg =
reinterpret_cast<const unsigned char*>("0\r\n1234567890123456\r\n");
CPPUNIT_ASSERT_EQUAL(std::string("1234567890123456"),
decoder.decode(msg.c_str(), msg.size()));
}
// Not all chunk data is available
{
std::basic_string<unsigned char> msg =
reinterpret_cast<const unsigned char*>("10\r\n1234567890");
CPPUNIT_ASSERT_EQUAL(std::string("1234567890"),
decoder.decode(msg.c_str(), msg.size()));
}
{
std::basic_string<unsigned char> msg =
reinterpret_cast<const unsigned char*>("123456\r\n");
CPPUNIT_ASSERT_EQUAL(std::string("123456"),
decoder.decode(msg.c_str(), msg.size()));
}
// no trailing CR LF.
{
std::basic_string<unsigned char> msg =
reinterpret_cast<const unsigned char*>
("10\r\n1234567890123456");
CPPUNIT_ASSERT_EQUAL(std::string("1234567890123456"),
decoder.decode(msg.c_str(), msg.size()));
}
// feed only CR
{
std::basic_string<unsigned char> msg =
reinterpret_cast<const unsigned char*>
("\r");
CPPUNIT_ASSERT_EQUAL(std::string(),
decoder.decode(msg.c_str(), msg.size()));
}
// feed next LF
{
std::basic_string<unsigned char> msg =
reinterpret_cast<const unsigned char*>
("\n");
CPPUNIT_ASSERT_EQUAL(std::string(),
decoder.decode(msg.c_str(), msg.size()));
}
// feed 0 CR LF.
{
std::basic_string<unsigned char> msg =
reinterpret_cast<const unsigned char*>
("0\r\n");
CPPUNIT_ASSERT_EQUAL(std::string(),
decoder.decode(msg.c_str(), msg.size()));
}
// input is over
CPPUNIT_ASSERT(decoder.finished());
decoder.release();
}
void ChunkedDecoderTest::testDecode_tooLargeChunkSize()
{
// Feed chunkSize == ChunkedDecoder::MAX_CHUNK_SIZE + 1 == 0x100001.
std::basic_string<unsigned char> msg =
reinterpret_cast<const unsigned char*>("100001\r\n");
ChunkedDecoder decoder;
try {
decoder.decode(msg.c_str(), msg.size());
CPPUNIT_FAIL("exception must be thrown.");
} catch(DlAbortEx& e) {
// success
}
}
void ChunkedDecoderTest::testDecode_chunkSizeMismatch()
{
std::basic_string<unsigned char> msg =
reinterpret_cast<const unsigned char*>("3\r\n1234\r\n");
ChunkedDecoder decoder;
try {
decoder.decode(msg.c_str(), msg.size());
CPPUNIT_FAIL("exception must be thrown.");
} catch(DlAbortEx& e) {
// success
}
}
void ChunkedDecoderTest::testGetName()
{
ChunkedDecoder decoder;
CPPUNIT_ASSERT_EQUAL(std::string("ChunkedDecoder"), decoder.getName());
}
} // namespace aria2

View File

@ -1,70 +0,0 @@
#include "ChunkedEncoding.h"
#include <fstream>
#include <iostream>
#include <string>
#include <cppunit/extensions/HelperMacros.h>
namespace aria2 {
class ChunkedEncodingTest:public CppUnit::TestFixture {
CPPUNIT_TEST_SUITE(ChunkedEncodingTest);
CPPUNIT_TEST(testInflate1);
CPPUNIT_TEST(testInflateLargeChunk);
CPPUNIT_TEST_SUITE_END();
private:
ChunkedEncoding* enc;
public:
void setUp() {
enc = new ChunkedEncoding();
enc->init();
}
void testInflate1();
void testInflateLargeChunk();
};
CPPUNIT_TEST_SUITE_REGISTRATION( ChunkedEncodingTest );
void ChunkedEncodingTest::testInflate1() {
std::string msg = "a\r\n1234567890\r\n";
unsigned char buf[100];
size_t len = sizeof(buf);
enc->inflate(buf, len,
reinterpret_cast<const unsigned char*>(msg.c_str()), msg.size());
CPPUNIT_ASSERT_EQUAL(std::string("1234567890"), std::string(&buf[0], &buf[len]));
// second pass
len = sizeof(buf);
msg = "3;extensionIgnored\r\n123\r\n0\r\n";
enc->inflate(buf, len,
reinterpret_cast<const unsigned char*>(msg.c_str()), msg.size());
CPPUNIT_ASSERT_EQUAL(std::string("123"), std::string(&buf[0], &buf[len]));
// input is over
CPPUNIT_ASSERT(enc->finished());
}
void ChunkedEncodingTest::testInflateLargeChunk() {
// give over 4096 character chunk
std::fstream is("4096chunk.txt", std::ios::in);
if(is.fail()) {
CPPUNIT_FAIL("cannot open file 4096chunk.txt");
}
std::string body;
is >> body;
unsigned char buf[4097];
size_t len = sizeof(buf);
for(int i = 0; i < 2; i++) {
std::string msg = "1000\r\n"+body+"\r\n";
len = sizeof(buf);
enc->inflate(buf, len,
reinterpret_cast<const unsigned char*>(msg.c_str()), msg.size());
CPPUNIT_ASSERT_EQUAL(body, std::string(&buf[0], &buf[len]));
}
enc->inflate(buf, len, reinterpret_cast<const unsigned char*>("0\r\n"), 3);
CPPUNIT_ASSERT_EQUAL((size_t)0, len);
CPPUNIT_ASSERT(enc->finished());
}
} // namespace aria2

View File

@ -2,7 +2,6 @@
#include "prefs.h" #include "prefs.h"
#include "PiecedSegment.h" #include "PiecedSegment.h"
#include "Piece.h" #include "Piece.h"
#include "TransferEncoding.h"
#include "Request.h" #include "Request.h"
#include "HttpHeader.h" #include "HttpHeader.h"
#include "HttpRequest.h" #include "HttpRequest.h"
@ -30,7 +29,7 @@ class HttpResponseTest : public CppUnit::TestFixture {
CPPUNIT_TEST(testIsRedirect); CPPUNIT_TEST(testIsRedirect);
CPPUNIT_TEST(testIsTransferEncodingSpecified); CPPUNIT_TEST(testIsTransferEncodingSpecified);
CPPUNIT_TEST(testGetTransferEncoding); CPPUNIT_TEST(testGetTransferEncoding);
CPPUNIT_TEST(testGetTransferDecoder); CPPUNIT_TEST(testGetTransferEncodingDecoder);
CPPUNIT_TEST(testIsContentEncodingSpecified); CPPUNIT_TEST(testIsContentEncodingSpecified);
CPPUNIT_TEST(testGetContentEncoding); CPPUNIT_TEST(testGetContentEncoding);
CPPUNIT_TEST(testGetContentEncodingDecoder); CPPUNIT_TEST(testGetContentEncodingDecoder);
@ -58,7 +57,7 @@ public:
void testIsRedirect(); void testIsRedirect();
void testIsTransferEncodingSpecified(); void testIsTransferEncodingSpecified();
void testGetTransferEncoding(); void testGetTransferEncoding();
void testGetTransferDecoder(); void testGetTransferEncodingDecoder();
void testIsContentEncodingSpecified(); void testIsContentEncodingSpecified();
void testGetContentEncoding(); void testGetContentEncoding();
void testGetContentEncodingDecoder(); void testGetContentEncodingDecoder();
@ -134,7 +133,8 @@ void HttpResponseTest::testDeterminFilename_without_ContentDisposition()
httpResponse.determinFilename()); httpResponse.determinFilename());
} }
void HttpResponseTest::testDeterminFilename_with_ContentDisposition_zero_length() void HttpResponseTest::testDeterminFilename_with_ContentDisposition_zero_length
()
{ {
HttpResponse httpResponse; HttpResponse httpResponse;
SharedHandle<HttpHeader> httpHeader(new HttpHeader()); SharedHandle<HttpHeader> httpHeader(new HttpHeader());
@ -155,7 +155,8 @@ void HttpResponseTest::testDeterminFilename_with_ContentDisposition()
{ {
HttpResponse httpResponse; HttpResponse httpResponse;
SharedHandle<HttpHeader> httpHeader(new HttpHeader()); SharedHandle<HttpHeader> httpHeader(new HttpHeader());
httpHeader->put("Content-Disposition", "attachment; filename=\"aria2-current.tar.bz2\""); httpHeader->put("Content-Disposition",
"attachment; filename=\"aria2-current.tar.bz2\"");
SharedHandle<HttpRequest> httpRequest(new HttpRequest()); SharedHandle<HttpRequest> httpRequest(new HttpRequest());
SharedHandle<Request> request(new Request()); SharedHandle<Request> request(new Request());
request->setUrl("http://localhost/archives/aria2-1.0.0.tar.bz2"); request->setUrl("http://localhost/archives/aria2-1.0.0.tar.bz2");
@ -186,8 +187,9 @@ void HttpResponseTest::testGetRedirectURI_with_Location()
httpHeader->put("Location", "http://localhost/download/aria2-1.0.0.tar.bz2"); httpHeader->put("Location", "http://localhost/download/aria2-1.0.0.tar.bz2");
httpResponse.setHttpHeader(httpHeader); httpResponse.setHttpHeader(httpHeader);
CPPUNIT_ASSERT_EQUAL(std::string("http://localhost/download/aria2-1.0.0.tar.bz2"), CPPUNIT_ASSERT_EQUAL
httpResponse.getRedirectURI()); (std::string("http://localhost/download/aria2-1.0.0.tar.bz2"),
httpResponse.getRedirectURI());
} }
void HttpResponseTest::testIsRedirect() void HttpResponseTest::testIsRedirect()
@ -231,21 +233,22 @@ void HttpResponseTest::testGetTransferEncoding()
httpHeader->put("Transfer-Encoding", "chunked"); httpHeader->put("Transfer-Encoding", "chunked");
CPPUNIT_ASSERT_EQUAL(std::string("chunked"), httpResponse.getTransferEncoding()); CPPUNIT_ASSERT_EQUAL(std::string("chunked"),
httpResponse.getTransferEncoding());
} }
void HttpResponseTest::testGetTransferDecoder() void HttpResponseTest::testGetTransferEncodingDecoder()
{ {
HttpResponse httpResponse; HttpResponse httpResponse;
SharedHandle<HttpHeader> httpHeader(new HttpHeader()); SharedHandle<HttpHeader> httpHeader(new HttpHeader());
httpResponse.setHttpHeader(httpHeader); httpResponse.setHttpHeader(httpHeader);
CPPUNIT_ASSERT(httpResponse.getTransferDecoder().isNull()); CPPUNIT_ASSERT(httpResponse.getTransferEncodingDecoder().isNull());
httpHeader->put("Transfer-Encoding", "chunked"); httpHeader->put("Transfer-Encoding", "chunked");
CPPUNIT_ASSERT(!httpResponse.getTransferDecoder().isNull()); CPPUNIT_ASSERT(!httpResponse.getTransferEncodingDecoder().isNull());
} }
void HttpResponseTest::testIsContentEncodingSpecified() void HttpResponseTest::testIsContentEncodingSpecified()

View File

@ -40,7 +40,6 @@ aria2c_SOURCES = AllTest.cc\
HttpHeaderTest.cc\ HttpHeaderTest.cc\
HttpResponseTest.cc\ HttpResponseTest.cc\
SharedHandleTest.cc\ SharedHandleTest.cc\
ChunkedEncodingTest.cc\
FileTest.cc\ FileTest.cc\
OptionTest.cc\ OptionTest.cc\
DefaultDiskWriterTest.cc\ DefaultDiskWriterTest.cc\
@ -52,7 +51,8 @@ aria2c_SOURCES = AllTest.cc\
ProtocolDetectorTest.cc\ ProtocolDetectorTest.cc\
StringFormatTest.cc\ StringFormatTest.cc\
ExceptionTest.cc\ ExceptionTest.cc\
DownloadHandlerFactoryTest.cc DownloadHandlerFactoryTest.cc\
ChunkedDecoderTest.cc
if HAVE_LIBZ if HAVE_LIBZ
aria2c_SOURCES += GZipDecoderTest.cc aria2c_SOURCES += GZipDecoderTest.cc

View File

@ -182,13 +182,13 @@ am__aria2c_SOURCES_DIST = AllTest.cc SocketCoreTest.cc \
NetrcAuthResolverTest.cc DefaultAuthResolverTest.cc \ NetrcAuthResolverTest.cc DefaultAuthResolverTest.cc \
OptionHandlerTest.cc SegmentManTest.cc BitfieldManTest.cc \ OptionHandlerTest.cc SegmentManTest.cc BitfieldManTest.cc \
NetrcTest.cc SingletonHolderTest.cc HttpHeaderTest.cc \ NetrcTest.cc SingletonHolderTest.cc HttpHeaderTest.cc \
HttpResponseTest.cc SharedHandleTest.cc ChunkedEncodingTest.cc \ HttpResponseTest.cc SharedHandleTest.cc FileTest.cc \
FileTest.cc OptionTest.cc DefaultDiskWriterTest.cc \ OptionTest.cc DefaultDiskWriterTest.cc FeatureConfigTest.cc \
FeatureConfigTest.cc SpeedCalcTest.cc MultiDiskAdaptorTest.cc \ SpeedCalcTest.cc MultiDiskAdaptorTest.cc \
MultiFileAllocationIteratorTest.cc FixedNumberRandomizer.h \ MultiFileAllocationIteratorTest.cc FixedNumberRandomizer.h \
ProtocolDetectorTest.cc StringFormatTest.cc ExceptionTest.cc \ ProtocolDetectorTest.cc StringFormatTest.cc ExceptionTest.cc \
DownloadHandlerFactoryTest.cc GZipDecoderTest.cc \ DownloadHandlerFactoryTest.cc ChunkedDecoderTest.cc \
MessageDigestHelperTest.cc \ GZipDecoderTest.cc MessageDigestHelperTest.cc \
IteratableChunkChecksumValidatorTest.cc \ IteratableChunkChecksumValidatorTest.cc \
IteratableChecksumValidatorTest.cc BtAllowedFastMessageTest.cc \ IteratableChecksumValidatorTest.cc BtAllowedFastMessageTest.cc \
BtBitfieldMessageTest.cc BtCancelMessageTest.cc \ BtBitfieldMessageTest.cc BtCancelMessageTest.cc \
@ -345,15 +345,15 @@ am_aria2c_OBJECTS = AllTest.$(OBJEXT) SocketCoreTest.$(OBJEXT) \
SegmentManTest.$(OBJEXT) BitfieldManTest.$(OBJEXT) \ SegmentManTest.$(OBJEXT) BitfieldManTest.$(OBJEXT) \
NetrcTest.$(OBJEXT) SingletonHolderTest.$(OBJEXT) \ NetrcTest.$(OBJEXT) SingletonHolderTest.$(OBJEXT) \
HttpHeaderTest.$(OBJEXT) HttpResponseTest.$(OBJEXT) \ HttpHeaderTest.$(OBJEXT) HttpResponseTest.$(OBJEXT) \
SharedHandleTest.$(OBJEXT) ChunkedEncodingTest.$(OBJEXT) \ SharedHandleTest.$(OBJEXT) FileTest.$(OBJEXT) \
FileTest.$(OBJEXT) OptionTest.$(OBJEXT) \ OptionTest.$(OBJEXT) DefaultDiskWriterTest.$(OBJEXT) \
DefaultDiskWriterTest.$(OBJEXT) FeatureConfigTest.$(OBJEXT) \ FeatureConfigTest.$(OBJEXT) SpeedCalcTest.$(OBJEXT) \
SpeedCalcTest.$(OBJEXT) MultiDiskAdaptorTest.$(OBJEXT) \ MultiDiskAdaptorTest.$(OBJEXT) \
MultiFileAllocationIteratorTest.$(OBJEXT) \ MultiFileAllocationIteratorTest.$(OBJEXT) \
ProtocolDetectorTest.$(OBJEXT) StringFormatTest.$(OBJEXT) \ ProtocolDetectorTest.$(OBJEXT) StringFormatTest.$(OBJEXT) \
ExceptionTest.$(OBJEXT) DownloadHandlerFactoryTest.$(OBJEXT) \ ExceptionTest.$(OBJEXT) DownloadHandlerFactoryTest.$(OBJEXT) \
$(am__objects_1) $(am__objects_2) $(am__objects_3) \ ChunkedDecoderTest.$(OBJEXT) $(am__objects_1) $(am__objects_2) \
$(am__objects_4) $(am__objects_3) $(am__objects_4)
aria2c_OBJECTS = $(am_aria2c_OBJECTS) aria2c_OBJECTS = $(am_aria2c_OBJECTS)
am__DEPENDENCIES_1 = am__DEPENDENCIES_1 =
aria2c_DEPENDENCIES = ../src/libaria2c.a $(am__DEPENDENCIES_1) aria2c_DEPENDENCIES = ../src/libaria2c.a $(am__DEPENDENCIES_1)
@ -562,13 +562,14 @@ aria2c_SOURCES = AllTest.cc SocketCoreTest.cc array_funTest.cc \
NetrcAuthResolverTest.cc DefaultAuthResolverTest.cc \ NetrcAuthResolverTest.cc DefaultAuthResolverTest.cc \
OptionHandlerTest.cc SegmentManTest.cc BitfieldManTest.cc \ OptionHandlerTest.cc SegmentManTest.cc BitfieldManTest.cc \
NetrcTest.cc SingletonHolderTest.cc HttpHeaderTest.cc \ NetrcTest.cc SingletonHolderTest.cc HttpHeaderTest.cc \
HttpResponseTest.cc SharedHandleTest.cc ChunkedEncodingTest.cc \ HttpResponseTest.cc SharedHandleTest.cc FileTest.cc \
FileTest.cc OptionTest.cc DefaultDiskWriterTest.cc \ OptionTest.cc DefaultDiskWriterTest.cc FeatureConfigTest.cc \
FeatureConfigTest.cc SpeedCalcTest.cc MultiDiskAdaptorTest.cc \ SpeedCalcTest.cc MultiDiskAdaptorTest.cc \
MultiFileAllocationIteratorTest.cc FixedNumberRandomizer.h \ MultiFileAllocationIteratorTest.cc FixedNumberRandomizer.h \
ProtocolDetectorTest.cc StringFormatTest.cc ExceptionTest.cc \ ProtocolDetectorTest.cc StringFormatTest.cc ExceptionTest.cc \
DownloadHandlerFactoryTest.cc $(am__append_1) $(am__append_2) \ DownloadHandlerFactoryTest.cc ChunkedDecoderTest.cc \
$(am__append_3) $(am__append_4) $(am__append_1) $(am__append_2) $(am__append_3) \
$(am__append_4)
#aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64 #aria2c_CXXFLAGS = ${CPPUNIT_CFLAGS} -I../src -I../lib -Wall -D_FILE_OFFSET_BITS=64
#aria2c_LDFLAGS = ${CPPUNIT_LIBS} #aria2c_LDFLAGS = ${CPPUNIT_LIBS}
@ -683,7 +684,7 @@ distclean-compile:
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtSuggestPieceMessageTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtSuggestPieceMessageTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtUnchokeMessageTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/BtUnchokeMessageTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ByteArrayDiskWriterTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ByteArrayDiskWriterTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ChunkedEncodingTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/ChunkedDecoderTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CookieBoxFactoryTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CookieBoxFactoryTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CookieBoxTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CookieBoxTest.Po@am__quote@
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CookieParserTest.Po@am__quote@ @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/CookieParserTest.Po@am__quote@