ChunkedEncoding.cc 5.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194
  1. /* <!-- copyright */
  2. /*
  3. * aria2 - The high speed download utility
  4. *
  5. * Copyright (C) 2006 Tatsuhiro Tsujikawa
  6. *
  7. * This program is free software; you can redistribute it and/or modify
  8. * it under the terms of the GNU General Public License as published by
  9. * the Free Software Foundation; either version 2 of the License, or
  10. * (at your option) any later version.
  11. *
  12. * This program is distributed in the hope that it will be useful,
  13. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  14. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  15. * GNU General Public License for more details.
  16. *
  17. * You should have received a copy of the GNU General Public License
  18. * along with this program; if not, write to the Free Software
  19. * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
  20. *
  21. * In addition, as a special exception, the copyright holders give
  22. * permission to link the code of portions of this program with the
  23. * OpenSSL library under certain conditions as described in each
  24. * individual source file, and distribute linked combinations
  25. * including the two.
  26. * You must obey the GNU General Public License in all respects
  27. * for all of the code used other than OpenSSL. If you modify
  28. * file(s) with this exception, you may extend this exception to your
  29. * version of the file(s), but you are not obligated to do so. If you
  30. * do not wish to do so, delete this exception statement from your
  31. * version. If you delete this exception statement from all source
  32. * files in the program, then also delete it here.
  33. */
  34. /* copyright --> */
  35. #include "ChunkedEncoding.h"
  36. #include "DlAbortEx.h"
  37. #include "message.h"
  38. #include "Util.h"
  39. #include "StringFormat.h"
  40. #include <cstring>
  41. namespace aria2 {
  42. #define MAX_BUFSIZE (1024*1024)
  43. ChunkedEncoding::ChunkedEncoding() {
  44. strbufSize = 4096;
  45. strbuf = new unsigned char[strbufSize];
  46. strbufTail = strbuf;
  47. state = READ_SIZE;
  48. chunkSize = 0;
  49. }
  50. ChunkedEncoding::~ChunkedEncoding() {
  51. delete [] strbuf;
  52. }
  53. void ChunkedEncoding::init() {
  54. }
  55. bool ChunkedEncoding::finished() {
  56. return state == FINISH ? true : false;
  57. }
  58. void ChunkedEncoding::end() {}
  59. void ChunkedEncoding::inflate(unsigned char* outbuf, size_t& outlen,
  60. const unsigned char* inbuf, size_t inlen) {
  61. addBuffer(inbuf, inlen);
  62. unsigned char* p = strbuf;
  63. size_t clen = 0;
  64. while(1) {
  65. if(state == READ_SIZE) {
  66. if(readChunkSize(&p) == 0) {
  67. if(chunkSize == 0) {
  68. state = FINISH;
  69. } else {
  70. state = READ_DATA;
  71. }
  72. } else {
  73. // chunk size is not fully received.
  74. break;
  75. }
  76. } else if(state == READ_DATA) {
  77. if(readData(&p, outbuf, clen, outlen) == 0) {
  78. state = READ_SIZE;
  79. } else {
  80. break;
  81. }
  82. } else {
  83. break;
  84. }
  85. // all bytes in strbuf were examined?
  86. if(strbufTail <= p) {
  87. break;
  88. }
  89. }
  90. if(strbufTail <= p) {
  91. strbufTail = strbuf;
  92. } else {
  93. // copy string between [p, strbufTail]
  94. size_t unreadSize = strbufTail-p;
  95. unsigned char* temp = new unsigned char[strbufSize];
  96. memcpy(temp, p, unreadSize);
  97. delete [] strbuf;
  98. strbuf = temp;
  99. strbufTail = strbuf+unreadSize;
  100. }
  101. outlen = clen;
  102. }
  103. int ChunkedEncoding::readData(unsigned char** pp,
  104. unsigned char* buf, size_t& len,
  105. size_t maxlen)
  106. {
  107. if(buf+len == buf+maxlen) {
  108. return -1;
  109. }
  110. if(chunkSize == 0) {
  111. return readDataEOL(pp);
  112. }
  113. size_t wsize;
  114. if((size_t)(strbufTail-*pp) < chunkSize) {
  115. wsize = std::min((size_t)(strbufTail-*pp), maxlen-len);
  116. } else {
  117. wsize = std::min(chunkSize, maxlen-len);
  118. }
  119. memcpy(buf+len, *pp, wsize);
  120. chunkSize -= wsize;
  121. len += wsize;
  122. *pp += wsize;
  123. if(chunkSize == 0) {
  124. return readDataEOL(pp);
  125. } else {
  126. return -1;
  127. }
  128. }
  129. int ChunkedEncoding::readDataEOL(unsigned char** pp) {
  130. unsigned char* np = reinterpret_cast<unsigned char*>(memchr(*pp, '\n', strbufTail-*pp));
  131. unsigned char* rp = reinterpret_cast<unsigned char*>(memchr(*pp, '\r', strbufTail-*pp));
  132. if(np != NULL && rp != NULL && np-rp == 1 && *pp == rp) {
  133. *pp += 2;
  134. return 0;
  135. } else if(strbufTail-*pp < 2) {
  136. return -1;
  137. } else {
  138. throw DlAbortEx(EX_INVALID_CHUNK_SIZE);
  139. }
  140. }
  141. int ChunkedEncoding::readChunkSize(unsigned char** pp) {
  142. // we read chunk-size from *pp
  143. unsigned char* p;
  144. unsigned char* np = reinterpret_cast<unsigned char*>(memchr(*pp, '\n', strbufTail-*pp));
  145. unsigned char* rp = reinterpret_cast<unsigned char*>(memchr(*pp, '\r', strbufTail-*pp));
  146. if(np == NULL || rp == NULL || np-rp != 1) {
  147. // \r\n is not found. Return -1
  148. return -1;
  149. }
  150. p = rp;
  151. // We ignore chunk-extension
  152. unsigned char* exsp = reinterpret_cast<unsigned char*>(memchr(*pp, ';', strbufTail-*pp));
  153. if(exsp == 0 || p < exsp) {
  154. exsp = p;
  155. }
  156. std::string temp(*pp, exsp);
  157. chunkSize = Util::parseInt(temp, 16);
  158. if(chunkSize < 0) {
  159. throw DlAbortEx(EX_INVALID_CHUNK_SIZE);
  160. }
  161. *pp = p+2;
  162. return 0;
  163. }
  164. void ChunkedEncoding::addBuffer(const unsigned char* inbuf, size_t inlen) {
  165. size_t realbufSize = strbufTail-strbuf;
  166. if(realbufSize+inlen >= strbufSize) {
  167. if(realbufSize+inlen > MAX_BUFSIZE) {
  168. throw DlAbortEx
  169. (StringFormat(EX_TOO_LARGE_CHUNK, realbufSize+inlen).str());
  170. }
  171. strbufSize = realbufSize+inlen;
  172. unsigned char* temp = new unsigned char[strbufSize];
  173. memcpy(temp, strbuf, realbufSize);
  174. delete [] strbuf;
  175. strbuf = temp;
  176. strbufTail = strbuf+realbufSize;
  177. }
  178. memcpy(strbufTail, inbuf, inlen);
  179. strbufTail += inlen;
  180. }
  181. } // namespace aria2