131 |
131 |
132 self.saved_status = None |
132 self.saved_status = None |
133 self.saved_headers = [] |
133 self.saved_headers = [] |
134 self.sent_headers = False |
134 self.sent_headers = False |
135 self.length = None |
135 self.length = None |
|
136 self._chunked = None |
136 for chunk in self.server.application(env, self._start_response): |
137 for chunk in self.server.application(env, self._start_response): |
137 self._write(chunk) |
138 self._write(chunk) |
138 if not self.sent_headers: |
139 if not self.sent_headers: |
139 self.send_headers() |
140 self.send_headers() |
|
141 self._done() |
140 |
142 |
141 def send_headers(self): |
143 def send_headers(self): |
142 if not self.saved_status: |
144 if not self.saved_status: |
143 raise AssertionError("Sending headers before " |
145 raise AssertionError("Sending headers before " |
144 "start_response() called") |
146 "start_response() called") |
145 saved_status = self.saved_status.split(None, 1) |
147 saved_status = self.saved_status.split(None, 1) |
146 saved_status[0] = int(saved_status[0]) |
148 saved_status[0] = int(saved_status[0]) |
147 self.send_response(*saved_status) |
149 self.send_response(*saved_status) |
148 should_close = True |
150 self.length = None |
|
151 self._chunked = False |
149 for h in self.saved_headers: |
152 for h in self.saved_headers: |
150 self.send_header(*h) |
153 self.send_header(*h) |
151 if h[0].lower() == 'content-length': |
154 if h[0].lower() == 'content-length': |
152 should_close = False |
|
153 self.length = int(h[1]) |
155 self.length = int(h[1]) |
154 # The value of the Connection header is a list of case-insensitive |
156 if self.length is None: |
155 # tokens separated by commas and optional whitespace. |
157 self._chunked = (not self.close_connection and |
156 if should_close: |
158 self.request_version == "HTTP/1.1") |
157 self.send_header('Connection', 'close') |
159 if self._chunked: |
|
160 self.send_header('Transfer-Encoding', 'chunked') |
|
161 else: |
|
162 self.send_header('Connection', 'close') |
158 self.end_headers() |
163 self.end_headers() |
159 self.sent_headers = True |
164 self.sent_headers = True |
160 |
165 |
161 def _start_response(self, http_status, headers, exc_info=None): |
166 def _start_response(self, http_status, headers, exc_info=None): |
162 code, msg = http_status.split(None, 1) |
167 code, msg = http_status.split(None, 1) |
175 if self.length is not None: |
180 if self.length is not None: |
176 if len(data) > self.length: |
181 if len(data) > self.length: |
177 raise AssertionError("Content-length header sent, but more " |
182 raise AssertionError("Content-length header sent, but more " |
178 "bytes than specified are being written.") |
183 "bytes than specified are being written.") |
179 self.length = self.length - len(data) |
184 self.length = self.length - len(data) |
|
185 elif self._chunked and data: |
|
186 data = '%x\r\n%s\r\n' % (len(data), data) |
180 self.wfile.write(data) |
187 self.wfile.write(data) |
181 self.wfile.flush() |
188 self.wfile.flush() |
|
189 |
|
190 def _done(self): |
|
191 if self._chunked: |
|
192 self.wfile.write('0\r\n\r\n') |
|
193 self.wfile.flush() |
182 |
194 |
183 class _httprequesthandleropenssl(_httprequesthandler): |
195 class _httprequesthandleropenssl(_httprequesthandler): |
184 """HTTPS handler based on pyOpenSSL""" |
196 """HTTPS handler based on pyOpenSSL""" |
185 |
197 |
186 url_scheme = 'https' |
198 url_scheme = 'https' |