Panda3D
identityStreamBuf.cxx
Go to the documentation of this file.
1 /**
2  * PANDA 3D SOFTWARE
3  * Copyright (c) Carnegie Mellon University. All rights reserved.
4  *
5  * All use of this software is subject to the terms of the revised BSD
6  * license. You should have received a copy of this license along
7  * with this source code in a file named "LICENSE."
8  *
9  * @file identityStreamBuf.cxx
10  * @author drose
11  * @date 2002-10-09
12  */
13 
14 #include "identityStreamBuf.h"
15 
16 // This module is not compiled if OpenSSL is not available.
17 #ifdef HAVE_OPENSSL
18 #include "httpChannel.h"
19 
20 /**
21  *
22  */
23 IdentityStreamBuf::
24 IdentityStreamBuf() {
25  _has_content_length = true;
26  _bytes_remaining = 0;
27  _wanted_nonblocking = false;
28  _read_state = ISocketStream::RS_initial;
29 
30 #ifdef PHAVE_IOSTREAM
31  _buffer = (char *)PANDA_MALLOC_ARRAY(4096);
32  char *ebuf = _buffer + 4096;
33  setg(_buffer, ebuf, ebuf);
34  setp(_buffer, ebuf);
35 
36 #else
37  allocate();
38  setg(base(), ebuf(), ebuf());
39  setp(base(), ebuf());
40 #endif
41 }
42 
43 /**
44  *
45  */
46 IdentityStreamBuf::
47 ~IdentityStreamBuf() {
48  close_read();
49 #ifdef PHAVE_IOSTREAM
50  PANDA_FREE_ARRAY(_buffer);
51 #endif
52 }
53 
54 /**
55  * If the document pointer is non-NULL, it will be updated with the length of
56  * the file as it is derived from the identity encoding.
57  */
58 void IdentityStreamBuf::
59 open_read(BioStreamPtr *source, HTTPChannel *doc,
60  bool has_content_length, size_t content_length) {
61  _source = source;
62  _has_content_length = has_content_length;
63  _wanted_nonblocking = doc->_wanted_nonblocking;
64  _bytes_remaining = content_length;
65  _read_state = ISocketStream::RS_reading;
66 }
67 
68 /**
69  *
70  */
71 void IdentityStreamBuf::
72 close_read() {
73  _source.clear();
74 }
75 
76 /**
77  * Called by the system istream implementation when its internal buffer needs
78  * more characters.
79  */
80 int IdentityStreamBuf::
81 underflow() {
82  // Sometimes underflow() is called even if the buffer is not empty.
83  if (gptr() >= egptr()) {
84  size_t buffer_size = egptr() - eback();
85  gbump(-(int)buffer_size);
86 
87  size_t num_bytes = buffer_size;
88  size_t read_count = read_chars(gptr(), buffer_size);
89 
90  if (read_count != num_bytes) {
91  // Oops, we didn't read what we thought we would.
92  if (read_count == 0) {
93  gbump(num_bytes);
94  return EOF;
95  }
96 
97  // Slide what we did read to the top of the buffer.
98  nassertr(read_count < num_bytes, EOF);
99  size_t delta = num_bytes - read_count;
100  memmove(gptr() + delta, gptr(), read_count);
101  gbump(delta);
102  }
103  }
104 
105  return (unsigned char)*gptr();
106 }
107 
108 
109 /**
110  * Gets some characters from the source stream.
111  */
112 size_t IdentityStreamBuf::
113 read_chars(char *start, size_t length) {
114  size_t read_count = 0;
115 
116  if (!_has_content_length) {
117  // If we have no restrictions on content length, read till end of file.
118  (*_source)->read(start, length);
119  read_count = (*_source)->gcount();
120 
121  if (!_wanted_nonblocking) {
122  while (read_count == 0 && !(*_source)->is_closed()) {
123  // Simulate blocking.
124  thread_yield();
125  (*_source)->read(start, length);
126  read_count = (*_source)->gcount();
127  }
128  }
129 
130  if (read_count == 0) {
131  if ((*_source)->is_closed()) {
132  // socket closed; we're done.
133  _read_state = ISocketStream::RS_complete;
134  }
135  return 0;
136  }
137 
138  } else {
139  // Extract some of the remaining bytes, but do not read past the
140  // content_length restriction.
141 
142  if (_bytes_remaining != 0) {
143  length = std::min(length, _bytes_remaining);
144  (*_source)->read(start, length);
145  read_count = (*_source)->gcount();
146  if (!_wanted_nonblocking) {
147  while (read_count == 0 && !(*_source)->is_closed()) {
148  // Simulate blocking.
149  thread_yield();
150  (*_source)->read(start, length);
151  read_count = (*_source)->gcount();
152  }
153  }
154  nassertr(read_count <= _bytes_remaining, 0);
155  _bytes_remaining -= read_count;
156 
157  if (read_count == 0) {
158  if ((*_source)->is_closed()) {
159  // socket closed unexpectedly; problem.
160  _read_state = ISocketStream::RS_error;
161  }
162  return 0;
163  }
164  }
165 
166  if (_bytes_remaining == 0) {
167  // We're done.
168  _read_state = ISocketStream::RS_complete;
169  }
170  }
171 
172  return read_count;
173 }
174 
175 #endif // HAVE_OPENSSL
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.
PANDA 3D SOFTWARE Copyright (c) Carnegie Mellon University.