Переглянути джерело

* ChunkedEncoding.{h,cc}: fixed the bug that if chunk data is binary,
decoding did not work properly.

Tatsuhiro Tsujikawa 19 роки тому
батько
коміт
a59301bef0
3 змінених файлів з 43 додано та 30 видалено
  1. 5 0
      ChangeLog
  2. 37 30
      src/ChunkedEncoding.cc
  3. 1 0
      src/ChunkedEncoding.h

+ 5 - 0
ChangeLog

@@ -1,3 +1,8 @@
+2006-03-09  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
+
+	* ChunkedEncoding.{h,cc}: fixed the bug that if chunk data is binary,
+	decoding did not work properly.
+
 2006-03-07  Tatsuhiro Tsujikawa  <tujikawa at rednoah dot com>
 
 	* DownloadEngine.h: included sys/time.h

+ 37 - 30
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;
 }

+ 1 - 0
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);