diff --git a/ChangeLog b/ChangeLog index 14399211..3ff83770 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,8 @@ +2006-03-09 Tatsuhiro Tsujikawa + + * ChunkedEncoding.{h,cc}: fixed the bug that if chunk data is binary, + decoding did not work properly. + 2006-03-07 Tatsuhiro Tsujikawa * DownloadEngine.h: included sys/time.h diff --git a/src/ChunkedEncoding.cc b/src/ChunkedEncoding.cc index a9bd694e..496f02aa 100644 --- a/src/ChunkedEncoding.cc +++ b/src/ChunkedEncoding.cc @@ -31,7 +31,7 @@ ChunkedEncoding::ChunkedEncoding() { strbufSize = 4096; strbuf = new char[strbufSize]; - strbuf[0] = '\0'; + strbufTail = strbuf; state = READ_SIZE; chunkSize = 0; } @@ -76,21 +76,21 @@ void ChunkedEncoding::inflate(char* outbuf, int& outlen, const char* inbuf, int } else { break; } - // Was all bytes in strbuf examined? - if(strbuf+strlen(strbuf) <= p) { + // all bytes in strbuf were examined? + if(strbufTail <= p) { break; } } - if(strbuf+strlen(strbuf) <= p) { - // make strbuf NULL-string - strbuf[0] = '\0'; + if(strbufTail <= p) { + strbufTail = strbuf; } else { - // copy string between [p, strbuf+strlen(strbuf)+1], +1 is for NULL - // character. + // copy string between [p, strbufTail] + int unreadSize = strbufTail-p; char* temp = new char[strbufSize]; - memcpy(temp, p, strbuf+strlen(strbuf)-p+1); + memcpy(temp, p, unreadSize); delete [] strbuf; strbuf = temp; + strbufTail = strbuf+unreadSize; } outlen = clen; } @@ -103,8 +103,8 @@ int ChunkedEncoding::readData(char** pp, char* buf, int& len, int maxlen) { return readDataEOL(pp); } int wsize; - if(strlen(*pp) < (unsigned long int)chunkSize) { - wsize = strlen(*pp) <= (unsigned int)maxlen-len ? strlen(*pp) : maxlen-len; + if(strbufTail-*pp < chunkSize) { + wsize = strbufTail-*pp <= maxlen-len ? strbufTail-*pp : maxlen-len; } else { wsize = chunkSize <= maxlen-len ? chunkSize : maxlen-len; } @@ -112,7 +112,6 @@ int ChunkedEncoding::readData(char** pp, char* buf, int& len, int maxlen) { chunkSize -= wsize; len += wsize; *pp += wsize; - if(chunkSize == 0) { return readDataEOL(pp); } else { @@ -121,54 +120,62 @@ int ChunkedEncoding::readData(char** pp, char* buf, int& len, int maxlen) { } int ChunkedEncoding::readDataEOL(char** pp) { - if(strstr(*pp, "\r\n") == *pp) { + char* np = (char*)memchr(*pp, '\n', strbufTail-*pp); + char* rp = (char*)memchr(*pp, '\r', strbufTail-*pp); + if(np != NULL && rp != NULL && np-rp == 1 && *pp == rp) { *pp += 2; return 0; - } else if(strlen(*pp) < 2) { + } else if(strbufTail-*pp < 2) { return -1; } else { throw new DlAbortEx(EX_INVALID_CHUNK_SIZE); } } -// strbuf is NULL terminated string, and inlen is strlen(strbuf). -// therefore, strbuf[inlen] = '\0' int ChunkedEncoding::readChunkSize(char** pp) { // we read chunk-size from *pp - char* p = strstr(*pp, "\r\n"); - // \r\n is not found. Return -1 - if(p == NULL) { + char* p; + char* np = (char*)memchr(*pp, '\n', strbufTail-*pp); + char* rp = (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 - char* exsp = index(*pp, ';'); + char* exsp = (char*)memchr(*pp, ';', strbufTail-*pp); if(exsp == NULL) { exsp = p; } // TODO check invalid characters in buffer - chunkSize = strtol(*pp, NULL, 16); + char* temp = new char[exsp-*pp+1]; + memcpy(temp, *pp, exsp-*pp); + temp[exsp-*pp] = '\0'; + + chunkSize = strtol(temp, NULL, 16); if(chunkSize < 0) { throw new DlAbortEx(EX_INVALID_CHUNK_SIZE); } else if(errno == ERANGE && (chunkSize == LONG_MAX || chunkSize == LONG_MIN)) { throw new DlAbortEx(strerror(errno)); } *pp = p+2; - return 0; } void ChunkedEncoding::addBuffer(const char* inbuf, int inlen) { - if(strlen(strbuf)+inlen >= (unsigned int)strbufSize) { - if(strlen(strbuf)+inlen+1 > MAX_BUFSIZE) { - throw new DlAbortEx(EX_TOO_LARGE_CHUNK, strlen(strbuf)+inlen+1); + int realbufSize = strbufTail-strbuf; + if(realbufSize+inlen >= strbufSize) { + if(realbufSize+inlen > MAX_BUFSIZE) { + throw new DlAbortEx(EX_TOO_LARGE_CHUNK, realbufSize+inlen); } - strbufSize = strlen(strbuf)+inlen+1; + strbufSize = realbufSize+inlen; char* temp = new char[strbufSize]; - memcpy(temp, strbuf, strlen(strbuf)+1); + memcpy(temp, strbuf, realbufSize); delete [] strbuf; strbuf = temp; + strbufTail = strbuf+realbufSize; } - int origlen = strlen(strbuf); - memcpy(strbuf+origlen, inbuf, inlen); - strbuf[origlen+inlen] = '\0'; + memcpy(strbufTail, inbuf, inlen); + strbufTail += inlen; } diff --git a/src/ChunkedEncoding.h b/src/ChunkedEncoding.h index 954f4bf9..94bc3242 100644 --- a/src/ChunkedEncoding.h +++ b/src/ChunkedEncoding.h @@ -35,6 +35,7 @@ private: int state; char* strbuf; int strbufSize; + char* strbufTail; int readChunkSize(char** pp); int readData(char** pp, char* buf, int& len, int maxlen);