Klaus Demo bjoern / 789115a
Fix #128: Properly deal with pseudo-files on Python 3 Jonas Haag 2 years ago
6 changed file(s) with 17 addition(s) and 25 deletion(s). Raw diff Collapse all Expand all
44 FileWrapper_New(PyTypeObject* cls, PyObject* args, PyObject* kwargs)
55 {
66 PyObject* file;
7 int fd;
78 unsigned int ignored_blocksize;
89
910 if(!PyArg_ParseTuple(args, "O|I:FileWrapper", &file, &ignored_blocksize))
1011 return NULL;
1112
12 if(!_File_Check(file)) {
13 TYPE_ERROR("FileWrapper argument", "file", file);
13 fd = PyObject_AsFileDescriptor(file);
14 if (fd == -1) {
1415 return NULL;
1516 }
1617
1920
2021 FileWrapper* wrapper = PyObject_NEW(FileWrapper, cls);
2122 wrapper->file = file;
23 wrapper->fd = fd;
2224
2325 return (PyObject*)wrapper;
2426 }
66 typedef struct {
77 PyObject_HEAD
88 PyObject* file;
9 int fd;
910 } FileWrapper;
1011
1112 void _init_filewrapper(void);
1414 #define _Bytes_Check(obj) PyBytes_Check(obj)
1515 #define _Bytes_Resize(obj, len) _PyBytes_Resize(obj, len)
1616 #define _FromLong(n) PyLong_FromLong(n)
17 #define _File_Check(file) (PyObject_HasAttrString(file, "fileno") && \
18 PyCallable_Check(PyObject_GetAttrString(file, "fileno")))
1917 #define _Unicode_EncodeLatin1(u) PyUnicode_AsLatin1String(u)
18
2019 #else
20
2121 #define _Bytes_AS_DATA(obj) PyString_AS_STRING(obj)
2222 #define _Bytes_FromString(name) PyString_FromString(name)
2323 #define _Unicode_FromString(name) PyString_FromString(name)
2828 #define _Bytes_Check(obj) PyString_Check(obj)
2929 #define _Bytes_Resize(obj, len) _PyString_Resize(obj, len)
3030 #define _FromLong(n) PyInt_FromLong(n)
31 #define _File_Check(file) PyFile_Check(file)
3231 #define _Unicode_EncodeLatin1(u) (Py_INCREF(u),u)
3332 #endif
3433
1515 unsigned keep_alive : 1;
1616 unsigned response_length_unknown : 1;
1717 unsigned chunked_response : 1;
18 unsigned use_sendfile : 1;
1918 } request_state;
2019
2120 typedef struct {
1111 # include <sys/signal.h>
1212 #endif
1313
14 #include "filewrapper.h"
1415 #include "portable_sendfile.h"
1516 #include "common.h"
1617 #include "wsgi.h"
245246 GIL_LOCK(0);
246247
247248 write_state write_state;
248 if(request->state.use_sendfile) {
249 if(FileWrapper_CheckExact(request->iterable)) {
249250 write_state = on_write_sendfile(mainloop, request);
250251 } else {
251252 write_state = on_write_chunk(mainloop, request);
287288 */
288289 if(request->current_chunk) {
289290 /* Phase A) -- current_chunk contains the HTTP headers */
290 if (do_send_chunk(request)) {
291 // data left to send in the current chunk
292 return not_yet_done;
293 } else {
294 assert(request->current_chunk == NULL);
295 assert(request->current_chunk_p == 0);
296 /* Transition to Phase B) -- abuse current_chunk_p to store the file fd */
297 request->current_chunk_p = PyObject_AsFileDescriptor(request->iterable);
298 // don't stop yet, Phase B is still missing
299 return not_yet_done;
300 }
301 } else {
302 /* Phase B) -- current_chunk_p contains file fd */
291 do_send_chunk(request);
292 // Either we have headers left to send, or current_chunk has been set to
293 // NULL and we'll fall into Phase B) on the next invocation.
294 return not_yet_done;
295 } else {
296 /* Phase B) */
303297 if (do_sendfile(request)) {
304298 // Haven't reached the end of file yet
305299 return not_yet_done;
406400 {
407401 Py_ssize_t bytes_sent = portable_sendfile(
408402 request->client_fd,
409 request->current_chunk_p /* current_chunk_p stores the file fd */
403 ((FileWrapper*)request->iterable)->fd
410404 );
411405 if(bytes_sent == -1)
412406 return handle_nonzero_errno(request);
8282 first_chunk = NULL;
8383 }
8484 } else if(FileWrapper_CheckExact(retval)) {
85 request->state.use_sendfile = true;
86 request->iterable = ((FileWrapper*)retval)->file;
87 Py_INCREF(request->iterable);
88 Py_DECREF(retval);
85 request->iterable = retval;
8986 request->iterator = NULL;
9087 first_chunk = NULL;
9188 } else {