00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #include "chunkedStreamBuf.h"
00016 #include "config_downloader.h"
00017 #include <ctype.h>
00018
00019
00020 #ifdef HAVE_OPENSSL
00021
00022 #ifndef HAVE_STREAMSIZE
00023
00024 typedef int streamsize;
00025 #endif
00026
00027
00028
00029
00030
00031
00032 ChunkedStreamBuf::
00033 ChunkedStreamBuf() {
00034 _chunk_remaining = 0;
00035 _done = true;
00036 _wanted_nonblocking = false;
00037 _read_state = ISocketStream::RS_initial;
00038
00039 #ifdef PHAVE_IOSTREAM
00040 _buffer = (char *)PANDA_MALLOC_ARRAY(4096);
00041 char *ebuf = _buffer + 4096;
00042 setg(_buffer, ebuf, ebuf);
00043 setp(_buffer, ebuf);
00044
00045 #else
00046 allocate();
00047 setg(base(), ebuf(), ebuf());
00048 setp(base(), ebuf());
00049 #endif
00050 }
00051
00052
00053
00054
00055
00056
00057 ChunkedStreamBuf::
00058 ~ChunkedStreamBuf() {
00059 close_read();
00060 #ifdef PHAVE_IOSTREAM
00061 PANDA_FREE_ARRAY(_buffer);
00062 #endif
00063 }
00064
00065
00066
00067
00068
00069
00070
00071
00072 void ChunkedStreamBuf::
00073 open_read(BioStreamPtr *source, HTTPChannel *doc) {
00074 _source = source;
00075 nassertv(!_source.is_null());
00076 _chunk_remaining = 0;
00077 _done = false;
00078 _wanted_nonblocking = doc->_wanted_nonblocking;
00079 _read_state = ISocketStream::RS_reading;
00080 _doc = doc;
00081
00082 if (_doc != (HTTPChannel *)NULL) {
00083 _read_index = doc->_read_index;
00084 _doc->_transfer_file_size = 0;
00085 _doc->_got_transfer_file_size = true;
00086
00087
00088
00089
00090 underflow();
00091 }
00092 }
00093
00094
00095
00096
00097
00098
00099 void ChunkedStreamBuf::
00100 close_read() {
00101 _source.clear();
00102 }
00103
00104
00105
00106
00107
00108
00109
00110 int ChunkedStreamBuf::
00111 underflow() {
00112
00113 if (gptr() >= egptr()) {
00114 size_t buffer_size = egptr() - eback();
00115 gbump(-(int)buffer_size);
00116
00117 size_t num_bytes = buffer_size;
00118 size_t read_count = read_chars(gptr(), buffer_size);
00119
00120 if (read_count != num_bytes) {
00121
00122 if (read_count == 0) {
00123 gbump(num_bytes);
00124 return EOF;
00125 }
00126
00127
00128 nassertr(read_count < num_bytes, EOF);
00129 size_t delta = num_bytes - read_count;
00130 memmove(gptr() + delta, gptr(), read_count);
00131 gbump(delta);
00132 }
00133 }
00134
00135 return (unsigned char)*gptr();
00136 }
00137
00138
00139
00140
00141
00142
00143
00144 size_t ChunkedStreamBuf::
00145 read_chars(char *start, size_t length) {
00146 while (true) {
00147 nassertr(!_source.is_null(), 0);
00148 if (_done) {
00149 return 0;
00150 }
00151
00152 if (_chunk_remaining != 0) {
00153
00154 length = min(length, _chunk_remaining);
00155 (*_source)->read(start, length);
00156 size_t read_count = (*_source)->gcount();
00157 if (!_wanted_nonblocking) {
00158 while (read_count == 0 && !(*_source)->is_closed()) {
00159
00160 thread_yield();
00161 (*_source)->read(start, length);
00162 read_count = (*_source)->gcount();
00163 }
00164 }
00165 _chunk_remaining -= read_count;
00166
00167 if (read_count == 0 && (*_source)->is_closed()) {
00168
00169 _read_state = ISocketStream::RS_error;
00170 }
00171
00172 return read_count;
00173 }
00174
00175
00176 string line;
00177 bool got_line = http_getline(line);
00178 while (got_line && line.empty()) {
00179
00180
00181
00182 got_line = http_getline(line);
00183 }
00184 if (!got_line) {
00185
00186 if ((*_source)->is_closed()) {
00187
00188 _read_state = ISocketStream::RS_error;
00189 }
00190
00191 if (!_wanted_nonblocking) {
00192
00193 thread_yield();
00194 continue;
00195 }
00196
00197 return 0;
00198 }
00199 size_t chunk_size = (size_t)strtol(line.c_str(), NULL, 16);
00200 if (downloader_cat.is_spam()) {
00201 downloader_cat.spam()
00202 << "Got chunk of size " << chunk_size << " bytes.\n";
00203 }
00204
00205 if (chunk_size == 0) {
00206
00207 _done = true;
00208 if (_doc != (HTTPChannel *)NULL && _read_index == _doc->_read_index) {
00209 _doc->_file_size = _doc->_transfer_file_size;
00210 _doc->_got_file_size = true;
00211 }
00212 _read_state = ISocketStream::RS_complete;
00213 return 0;
00214 }
00215
00216 if (_doc != (HTTPChannel *)NULL && _read_index == _doc->_read_index) {
00217 _doc->_transfer_file_size += chunk_size;
00218 }
00219
00220 _chunk_remaining = chunk_size;
00221
00222
00223 }
00224
00225
00226 return 0;
00227 }
00228
00229
00230
00231
00232
00233
00234
00235
00236
00237 bool ChunkedStreamBuf::
00238 http_getline(string &str) {
00239 nassertr(!_source.is_null(), false);
00240 int ch = (*_source)->get();
00241 while (!(*_source)->eof() && !(*_source)->fail()) {
00242 switch (ch) {
00243 case '\n':
00244
00245 str = _working_getline;
00246 _working_getline = string();
00247 {
00248
00249
00250 size_t p = str.length();
00251 while (p > 0 && isspace(str[p - 1])) {
00252 --p;
00253 }
00254 str = str.substr(0, p);
00255 }
00256
00257 return true;
00258
00259 case '\r':
00260
00261 break;
00262
00263 default:
00264 _working_getline += (char)ch;
00265 }
00266 ch = (*_source)->get();
00267 }
00268
00269 return false;
00270 }
00271
00272 #endif // HAVE_OPENSSL