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