Klaus Demo ~jonashaag/bjoern / d0220ed
Close #21: Call iterable.close() Jonas Haag 9 years ago
7 changed file(s) with 34 addition(s) and 18 deletion(s). Raw diff Collapse all Expand all
2828 void _initialize_static_strings()
2929 {
3030 #define _(name) _##name = PyString_FromString(#name)
31 _(REMOTE_ADDR); _(PATH_INFO); _(QUERY_STRING);
31 _(REMOTE_ADDR); _(PATH_INFO); _(QUERY_STRING); _(close);
3232 _(REQUEST_METHOD); _(SERVER_PROTOCOL); _(GET);
3333 _(HTTP_CONTENT_LENGTH); _(CONTENT_LENGTH); _(HTTP_CONTENT_TYPE); _(CONTENT_TYPE);
3434 _HTTP_1_1 = PyString_FromString("HTTP/1.1");
1313
1414 PyObject *_REMOTE_ADDR, *_PATH_INFO, *_QUERY_STRING, *_REQUEST_METHOD, *_GET,
1515 *_HTTP_CONTENT_LENGTH, *_CONTENT_LENGTH, *_HTTP_CONTENT_TYPE, *_CONTENT_TYPE,
16 *_SERVER_PROTOCOL, *_HTTP_1_1, *_HTTP_1_0, *_wsgi_input, *_empty_string;
16 *_SERVER_PROTOCOL, *_HTTP_1_1, *_HTTP_1_0, *_wsgi_input, *_close, *_empty_string;
1717
1818 #ifdef DEBUG
1919 #define DBG_REQ(request, ...) \
3636
3737 void Request_clean(Request* request)
3838 {
39 Py_XDECREF(request->iterable);
39 if(request->iterable) {
40 /* Call 'iterable.close()' if available */
41 PyObject* close_method = PyObject_GetAttr(request->iterable, _close);
42 if(close_method == NULL) {
43 if(PyErr_ExceptionMatches(PyExc_AttributeError))
44 PyErr_Clear();
45 } else {
46 PyObject_CallObject(close_method, NULL);
47 Py_DECREF(close_method);
48 }
49 if(PyErr_Occurred()) PyErr_Print();
50 Py_DECREF(request->iterable);
51 }
52 Py_XDECREF(request->iterator);
4053 Py_XDECREF(request->body);
4154 if(request->headers)
4255 assert(request->headers->ob_refcnt >= 1);
4141 PyObject* current_chunk;
4242 Py_ssize_t current_chunk_p;
4343 PyObject* iterable;
44 PyObject* iterator;
4445 PyObject* status;
4546 } Request;
4647
154154 DBG_REQ(request, "Parse error");
155155 request->current_chunk = PyString_FromString(
156156 http_error_messages[request->state.error_code]);
157 assert(request->iterable == NULL);
157 assert(request->iterator == NULL);
158158 }
159159 else if(request->state.parse_finished) {
160160 if(!wsgi_call_application(request)) {
161161 assert(PyErr_Occurred());
162162 PyErr_Print();
163163 assert(!request->state.chunked_response);
164 Py_XCLEAR(request->iterable);
164 Py_XCLEAR(request->iterator);
165165 request->current_chunk = PyString_FromString(
166166 http_error_messages[HTTP_SERVER_ERROR]);
167167 }
191191 if(send_chunk(request))
192192 goto out;
193193
194 if(request->iterable) {
194 if(request->iterator) {
195195 PyObject* next_chunk;
196196 next_chunk = wsgi_iterable_get_next_chunk(request);
197197 if(next_chunk) {
214214 Request_free(request);
215215 goto out;
216216 }
217 Py_DECREF(request->iterable);
218 request->iterable = NULL;
217 Py_CLEAR(request->iterator);
219218 }
220219 }
221220
270269 /* Serious transmission failure. Hang up. */
271270 fprintf(stderr, "Client %d hit errno %d\n", request->client_fd, errno);
272271 Py_DECREF(request->current_chunk);
273 Py_XCLEAR(request->iterable);
272 Py_XCLEAR(request->iterator);
274273 request->state.keep_alive = false;
275274 return false;
276275 }
278277
279278 request->current_chunk_p += sent_bytes;
280279 if(request->current_chunk_p == PyString_GET_SIZE(request->current_chunk)) {
281 Py_DECREF(request->current_chunk);
282 request->current_chunk = NULL;
280 Py_CLEAR(request->current_chunk);
283281 request->current_chunk_p = 0;
284282 return false;
285283 }
9191 }
9292 } else {
9393 /* Generic iterable (list of length != 1, generator, ...) */
94 PyObject* iter = PyObject_GetIter(retval);
95 Py_DECREF(retval);
96 if(iter == NULL)
94 request->iterable = retval;
95 request->iterator = PyObject_GetIter(retval);
96 if(request->iterator == NULL)
9797 return false;
98 request->iterable = iter;
9998 first_chunk = wsgi_iterable_get_next_chunk(request);
10099 if(first_chunk == NULL && PyErr_Occurred())
101100 return false;
121120 request->state.keep_alive = false;
122121 }
123122
124 /* Get the headers and concatenate the first body chunk to them.
123 /* Get the headers and concatenate the first body chunk.
125124 * In the first place this makes the code more simple because afterwards
126125 * we can throw away the first chunk PyObject; but it also is an optimization:
127126 * At least for small responses, the complete response could be sent with
229228 /* Get the next item out of ``request->iterable``, skipping empty ones. */
230229 PyObject* next;
231230 while(true) {
232 next = PyIter_Next(request->iterable);
231 next = PyIter_Next(request->iterator);
233232 if(next == NULL)
234233 return NULL;
235234 if(!PyString_Check(next)) {
1212 start_response('200 ok', (object(), object()))
1313 return ['yo']
1414
15 apps = [invalid_header_tuple_item, invalid_header_tuple, invalid_header_type]
16
17 def randomizer(*args, **kwargs):
18 return random.choice(apps)(*args, **kwargs)
19
1520 import bjoern
16 bjoern.run(invalid_header_type, '0.0.0.0', 8080)
21 bjoern.run(randomizer, '0.0.0.0', 8080)