static int uwsgi_ssh_request_file( struct wsgi_request *wsgi_req, char* filepath, struct uwsgi_ssh_mountpoint *usm ) { int sock = -1; int return_status = 0; LIBSSH2_SESSION *session = NULL; if (uwsgi_init_ssh_session(usm, &sock, &session)) { uwsgi_log("[SSH] session initialization failed. Is the SSH server up?\n"); return_status = 500; goto shutdown; } LIBSSH2_SFTP *sftp_session = NULL; do { sftp_session = libssh2_sftp_init(session); if (!sftp_session) { if ((libssh2_session_last_errno(session)) == LIBSSH2_ERROR_EAGAIN) { if (uwsgi_ssh_waitsocket(sock, session)) { return_status = 500; goto shutdown; } } else { uwsgi_error("uwsgi_ssh_request_file()/libssh2_sftp_init()"); return_status = 500; goto shutdown; } } } while (!sftp_session); // Request file stats via SFTP LIBSSH2_SFTP_ATTRIBUTES file_attrs; int rc; while ((rc = libssh2_sftp_stat(sftp_session, filepath, &file_attrs)) == LIBSSH2_ERROR_EAGAIN) { if (uwsgi_ssh_waitsocket(sock, session)) { return_status = 500; goto shutdown; } } if (rc < 0) { // If it fails, requested file could not exist. if (rc == LIBSSH2_ERROR_SFTP_PROTOCOL && libssh2_sftp_last_error(sftp_session) == LIBSSH2_FX_NO_SUCH_FILE) { return_status = 404; } else { uwsgi_error("uwsgi_ssh_request_file()/libssh2_sftp_stat()"); return_status = 500; } goto sftp_shutdown; } if (wsgi_req->if_modified_since_len) { time_t ims = uwsgi_parse_http_date(wsgi_req->if_modified_since, wsgi_req->if_modified_since_len); if (file_attrs.mtime <= (unsigned long)ims) { if (uwsgi_response_prepare_headers(wsgi_req, "304 Not Modified", 16) || uwsgi_response_write_headers_do(wsgi_req)) { uwsgi_error("uwsgi_parse_http_date()/uwsgi_response_prepare_headers(do)()"); } return_status = 500; goto sftp_shutdown; } } if (uwsgi_response_prepare_headers(wsgi_req, "200", 3)) { uwsgi_error("uwsgi_ssh_request_file()/uwsgi_response_prepare_headers()"); return_status = 500; goto sftp_shutdown; } if (uwsgi_response_add_content_length(wsgi_req, file_attrs.filesize)) { uwsgi_error("uwsgi_ssh_request_file()/uwsgi_response_add_content_length()"); return_status = 500; goto sftp_shutdown; } if (uwsgi_response_add_last_modified(wsgi_req, file_attrs.mtime)) { uwsgi_error("uwsgi_ssh_request_file()/uwsgi_response_add_last_modified()"); return_status = 500; goto sftp_shutdown; } size_t mime_type_len = 0; char *mime_type = uwsgi_get_mime_type(filepath, strlen(filepath), &mime_type_len); if (mime_type) { if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) { uwsgi_error("uwsgi_ssh_request_file()/uwsgi_response_add_content_type()"); // goto sftp_shutdown; } } // Request a file via SFTP LIBSSH2_SFTP_HANDLE *sftp_handle = NULL; do { sftp_handle = libssh2_sftp_open(sftp_session, filepath, LIBSSH2_FXF_READ, 0); if (!sftp_handle) { if (libssh2_session_last_errno(session) != LIBSSH2_ERROR_EAGAIN) { uwsgi_error("uwsgi_ssh_request_file()/libssh2_sftp_open()"); return_status = 500; goto sftp_shutdown; } else { if (uwsgi_ssh_waitsocket(sock, session)) { return_status = 500; goto sftp_shutdown; } } } } while (!sftp_handle); size_t buffer_size = uwsgi.page_size; void *buffer = alloca(buffer_size); libssh2_uint64_t read_size = 0; while (read_size < file_attrs.filesize) { rc = libssh2_sftp_read(sftp_handle, buffer, buffer_size); if (rc == LIBSSH2_ERROR_EAGAIN) { if (uwsgi_ssh_waitsocket(sock, session)) { return_status = 500; goto sftp_shutdown; } } else if (rc < 0) { uwsgi_error("uwsgi_ssh_request_file()/libssh2_sftp_read()"); break; } else { read_size += rc; if (uwsgi_response_write_body_do(wsgi_req, buffer, rc)) { uwsgi_error("uwsgi_ssh_request_file()/uwsgi_response_write_body_do()"); break; } } } while ((rc = libssh2_sftp_close(sftp_handle)) == LIBSSH2_ERROR_EAGAIN) { if (uwsgi_ssh_waitsocket(sock, session)) { return_status = 500; goto sftp_shutdown; } }; if (rc < 0) { uwsgi_error("uwsgi_ssh_request_file()/libssh2_sftp_close()"); } sftp_shutdown: while ((rc = libssh2_sftp_shutdown(sftp_session)) == LIBSSH2_ERROR_EAGAIN) { uwsgi_ssh_waitsocket(sock, session); } if (rc < 0) { uwsgi_error("uwsgi_ssh_request_file()/libssh2_sftp_shutdown()"); } shutdown: while (libssh2_session_disconnect(session, "Normal Shutdown, thank you!") == LIBSSH2_ERROR_EAGAIN) { uwsgi_ssh_waitsocket(sock, session); } libssh2_session_free(session); close(sock); libssh2_exit(); return return_status; }
int uwsgi_response_subhandler_web3(struct wsgi_request *wsgi_req) { PyObject *pychunk; // ok its a yield if (!wsgi_req->async_placeholder) { if (PyTuple_Check((PyObject *)wsgi_req->async_result)) { if (PyTuple_Size((PyObject *)wsgi_req->async_result) != 3) { uwsgi_log("invalid Web3 response.\n"); goto clear; } wsgi_req->async_placeholder = PyTuple_GetItem((PyObject *)wsgi_req->async_result, 0); Py_INCREF((PyObject *)wsgi_req->async_placeholder); PyObject *spit_args = PyTuple_New(2); PyObject *status = PyTuple_GetItem((PyObject *)wsgi_req->async_result, 1); Py_INCREF(status); PyTuple_SetItem(spit_args, 0, status); PyObject *headers = PyTuple_GetItem((PyObject *)wsgi_req->async_result, 2); Py_INCREF(headers); PyTuple_SetItem(spit_args, 1, headers); if (py_uwsgi_spit(Py_None, spit_args) == NULL) { PyErr_Print(); Py_DECREF(spit_args); goto clear; } Py_DECREF(spit_args); if (PyString_Check((PyObject *)wsgi_req->async_placeholder)) { char *content = PyString_AsString(wsgi_req->async_placeholder); size_t content_len = PyString_Size(wsgi_req->async_placeholder); UWSGI_RELEASE_GIL uwsgi_response_write_body_do(wsgi_req, content, content_len); UWSGI_GET_GIL uwsgi_py_check_write_errors { uwsgi_py_write_exception(wsgi_req); } goto clear; } PyObject *tmp = (PyObject *)wsgi_req->async_placeholder; wsgi_req->async_placeholder = PyObject_GetIter( (PyObject *)wsgi_req->async_placeholder ); Py_DECREF(tmp); if (!wsgi_req->async_placeholder) { goto clear; } if (uwsgi.async > 0) { return UWSGI_AGAIN; } } else {
int uwsgi_routing_func_file(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char buf[32768]; struct stat st; int ret = UWSGI_ROUTE_BREAK; size_t remains = 0; struct uwsgi_router_file_conf *urfc = (struct uwsgi_router_file_conf *) ur->data2; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->filename, urfc->filename_len); if (!ub) return UWSGI_ROUTE_BREAK; int fd = open(ub->buf, O_RDONLY); if (fd < 0) { if (ur->custom) ret = UWSGI_ROUTE_NEXT; goto end; } if (fstat(fd, &st)) { goto end2; } struct uwsgi_buffer *ub_s = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urfc->status, urfc->status_len); if (!ub_s) goto end2; if (urfc->no_headers) goto send; if (uwsgi_response_prepare_headers(wsgi_req, ub_s->buf, ub_s->pos)) { uwsgi_buffer_destroy(ub_s); goto end2; } uwsgi_buffer_destroy(ub_s); if (!urfc->no_cl) { if (uwsgi_response_add_content_length(wsgi_req, st.st_size)) goto end2; } if (urfc->mime) { size_t mime_type_len = 0; char *mime_type = uwsgi_get_mime_type(ub->buf, ub->pos, &mime_type_len); if (mime_type) { if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) goto end2; } else { if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2; } } else { if (uwsgi_response_add_content_type(wsgi_req, urfc->content_type, urfc->content_type_len)) goto end2; } send: remains = st.st_size; while(remains) { ssize_t rlen = read(fd, buf, UMIN(32768, remains)); if (rlen <= 0) goto end2; if (uwsgi_response_write_body_do(wsgi_req, buf, rlen)) goto end2; remains -= rlen; } end2: close(fd); end: uwsgi_buffer_destroy(ub); return ret; }
// this function does not use the magic api internally to avoid too much copy static void manage_magic_context(struct wsgi_request *wsgi_req, struct uwsgi_cache_magic_context *ucmc) { struct uwsgi_buffer *ub = NULL; struct uwsgi_cache *uc = uwsgi.caches; if (ucmc->cache_len > 0) { uc = uwsgi_cache_by_namelen(ucmc->cache, ucmc->cache_len); if (!uc) return; } if (!uc) return; // cache get if (!uwsgi_strncmp(ucmc->cmd, ucmc->cmd_len, "get", 3)) { uint64_t vallen = 0; uint64_t expires = 0; uwsgi_rlock(uc->lock); char *value = uwsgi_cache_get3(uc, ucmc->key, ucmc->key_len, &vallen, &expires); if (!value) { uwsgi_rwunlock(uc->lock); return; } // we are still locked !!! ub = uwsgi_buffer_new(uwsgi.page_size); ub->pos = 4; if (uwsgi_buffer_append_keyval(ub, "status", 6, "ok", 2)) goto error; if (uwsgi_buffer_append_keynum(ub, "size", 4, vallen)) goto error; if (expires) { if (uwsgi_buffer_append_keynum(ub, "expires", 7, expires)) goto error; } if (uwsgi_buffer_set_uh(ub, 111, 17)) goto error; if (uwsgi_buffer_append(ub, value, vallen)) goto error; // unlock !!! uwsgi_rwunlock(uc->lock); uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos); uwsgi_buffer_destroy(ub); return; } // cache exists if (!uwsgi_strncmp(ucmc->cmd, ucmc->cmd_len, "exists", 6)) { uwsgi_rlock(uc->lock); if (!uwsgi_cache_exists2(uc, ucmc->key, ucmc->key_len)) { uwsgi_rwunlock(uc->lock); return; } // we are still locked !!! ub = uwsgi_buffer_new(uwsgi.page_size); ub->pos = 4; if (uwsgi_buffer_append_keyval(ub, "status", 6, "ok", 2)) goto error; if (uwsgi_buffer_set_uh(ub, 111, 17)) goto error; // unlock !!! uwsgi_rwunlock(uc->lock); uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos); uwsgi_buffer_destroy(ub); return; } // cache del if (!uwsgi_strncmp(ucmc->cmd, ucmc->cmd_len, "del", 3)) { uwsgi_wlock(uc->lock); if (uwsgi_cache_del2(uc, ucmc->key, ucmc->key_len, 0, 0)) { uwsgi_rwunlock(uc->lock); return; } // we are still locked !!! ub = uwsgi_buffer_new(uwsgi.page_size); ub->pos = 4; if (uwsgi_buffer_append_keyval(ub, "status", 6, "ok", 2)) goto error; if (uwsgi_buffer_set_uh(ub, 111, 17)) goto error; // unlock !!! uwsgi_rwunlock(uc->lock); uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos); uwsgi_buffer_destroy(ub); return; } // cache clear if (!uwsgi_strncmp(ucmc->cmd, ucmc->cmd_len, "clear", 5)) { uint64_t i; uwsgi_wlock(uc->lock); for (i = 1; i < uwsgi.caches->max_items; i++) { if (uwsgi_cache_del2(uc, NULL, 0, i, 0)) { uwsgi_rwunlock(uc->lock); return; } } // we are still locked !!! ub = uwsgi_buffer_new(uwsgi.page_size); ub->pos = 4; if (uwsgi_buffer_append_keyval(ub, "status", 6, "ok", 2)) goto error; if (uwsgi_buffer_set_uh(ub, 111, 17)) goto error; // unlock !!! uwsgi_rwunlock(uc->lock); uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos); uwsgi_buffer_destroy(ub); return; } // cache set if (!uwsgi_strncmp(ucmc->cmd, ucmc->cmd_len, "set", 3) || !uwsgi_strncmp(ucmc->cmd, ucmc->cmd_len, "update", 6)) { if (ucmc->size == 0 || ucmc->size > uc->max_item_size) return; wsgi_req->post_cl = ucmc->size; // read the value ssize_t rlen = 0; char *value = uwsgi_request_body_read(wsgi_req, ucmc->size, &rlen); if (rlen != (ssize_t) ucmc->size) return; // ok let's lock uwsgi_wlock(uc->lock); if (uwsgi_cache_set2(uc, ucmc->key, ucmc->key_len, value, ucmc->size, ucmc->expires, ucmc->cmd_len > 3 ? UWSGI_CACHE_FLAG_UPDATE : 0)) { uwsgi_rwunlock(uc->lock); return; } // we are still locked !!! ub = uwsgi_buffer_new(uwsgi.page_size); ub->pos = 4; if (uwsgi_buffer_append_keyval(ub, "status", 6, "ok", 2)) goto error; if (uwsgi_buffer_set_uh(ub, 111, 17)) goto error; // unlock !!! uwsgi_rwunlock(uc->lock); uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos); uwsgi_buffer_destroy(ub); return; } return; error: uwsgi_rwunlock(uc->lock); uwsgi_buffer_destroy(ub); }
int uwsgi_python_send_body(struct wsgi_request *wsgi_req, PyObject *chunk) { char *content = NULL; size_t content_len = 0; #if defined(PYTHREE) || defined(Py_TPFLAGS_HAVE_NEWBUFFER) Py_buffer pbuf; int has_buffer = 0; #endif if (!up.wsgi_accept_buffer && !wsgi_req->is_raw) goto strict; #if defined(PYTHREE) || defined(Py_TPFLAGS_HAVE_NEWBUFFER) if (PyObject_CheckBuffer(chunk)) { if (!PyObject_GetBuffer(chunk, &pbuf, PyBUF_SIMPLE)) { content = (char *) pbuf.buf; content_len = (size_t) pbuf.len; has_buffer = 1; goto found; } } #else if (PyObject_CheckReadBuffer(chunk)) { #ifdef UWSGI_PYTHON_OLD int buffer_len = 0; if (!PyObject_AsCharBuffer(chunk, (const char **) &content, &buffer_len)) { #else if (!PyObject_AsCharBuffer(chunk, (const char **) &content, (Py_ssize_t *) &content_len)) { #endif PyErr_Clear(); goto found; } #ifdef UWSGI_PYTHON_OLD content_len = buffer_len; #endif } #endif strict: // fallback if (PyString_Check(chunk)) { content = PyString_AsString(chunk); content_len = PyString_Size(chunk); } found: if (content) { UWSGI_RELEASE_GIL uwsgi_response_write_body_do(wsgi_req, content, content_len); UWSGI_GET_GIL #if defined(PYTHREE) || defined(Py_TPFLAGS_HAVE_NEWBUFFER) if (has_buffer) PyBuffer_Release(&pbuf); #endif uwsgi_py_check_write_errors { uwsgi_py_write_exception(wsgi_req); return -1; } return 1; } return 0; } /* this is a hack for supporting non-file object passed to wsgi.file_wrapper */ static void uwsgi_python_consume_file_wrapper_read(struct wsgi_request *wsgi_req, PyObject *pychunk) { PyObject *read_method_args = NULL; PyObject *read_method = PyObject_GetAttrString(pychunk, "read"); if (wsgi_req->sendfile_fd_chunk > 0) { read_method_args = PyTuple_New(1); PyTuple_SetItem(read_method_args, 0, PyInt_FromLong(wsgi_req->sendfile_fd_chunk)); } else { read_method_args = PyTuple_New(0); } for(;;) { PyObject *read_method_output = PyEval_CallObject(read_method, read_method_args); if (PyErr_Occurred()) { uwsgi_manage_exception(wsgi_req, 0); break; } if (!read_method_output) break; if (PyString_Check(read_method_output)) { char *content = PyString_AsString(read_method_output); size_t content_len = PyString_Size(read_method_output); if (content_len == 0) { Py_DECREF(read_method_output); break; } UWSGI_RELEASE_GIL uwsgi_response_write_body_do(wsgi_req, content, content_len); UWSGI_GET_GIL } Py_DECREF(read_method_output); if (wsgi_req->sendfile_fd_chunk == 0) break; } Py_DECREF(read_method_args); Py_DECREF(read_method); }
static void uwsgi_rados_propfind(struct wsgi_request *wsgi_req, rados_ioctx_t ctx, char *key, uint64_t size, time_t mtime, int timeout) { // consume the body size_t remains = wsgi_req->post_cl; while(remains > 0) { ssize_t body_len = 0; char *body = uwsgi_request_body_read(wsgi_req, UMIN(remains, 32768), &body_len); if (!body || body == uwsgi.empty) break; remains -= body_len; } if (uwsgi_response_prepare_headers(wsgi_req, "207 Multi-Status", 16)) return; if (uwsgi_response_add_content_type(wsgi_req, "text/xml; charset=\"utf-8\"", 25)) return; struct uwsgi_buffer *ub = uwsgi_webdav_multistatus_new(); if (!ub) return; if (key) { size_t mime_type_len = 0; char *mime_type = uwsgi_get_mime_type(key, strlen(key), &mime_type_len); char *slashed = uwsgi_concat2("/", key); if (uwsgi_webdav_propfind_item_add(ub, slashed, strlen(key)+1, size, mtime, mime_type, mime_type_len, NULL, 0, NULL, 0)) { free(slashed); goto end; } free(slashed); if (uwsgi_webdav_multistatus_close(ub)) goto end; uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos); goto end; } // request for / size_t depth = 0; uint16_t http_depth_len = 0; char *http_depth = uwsgi_get_var(wsgi_req, "HTTP_DEPTH", 10, &http_depth_len); if (http_depth) { depth = uwsgi_str_num(http_depth, http_depth_len); } if (depth == 0) { if (uwsgi_webdav_propfind_item_add(ub, "/", 1, 0, 0, NULL, 0, NULL, 0, NULL, 0)) { goto end; } if (uwsgi_webdav_multistatus_close(ub)) goto end; uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos); goto end; } struct uwsgi_rados_io *urio = &urados.urio[wsgi_req->async_id]; rados_list_ctx_t ctx_list; if (rados_objects_list_open(ctx, &ctx_list) < 0) { goto end; } char *entry = NULL; while(rados_objects_list_next(ctx_list, (const char **)&entry, NULL) == 0) { uint64_t stat_size = 0; time_t stat_mtime = 0; if (uwsgi.async > 0) { if (uwsgi_rados_async_stat(urio, ctx, entry, &stat_size, &stat_mtime, timeout) < 0) goto end; } else { if (rados_stat(ctx, entry, &stat_size, &stat_mtime) < 0) goto end; } size_t mime_type_len = 0; char *mime_type = uwsgi_get_mime_type(entry, strlen(entry), &mime_type_len); char *slashed = uwsgi_concat2("/", entry); if (uwsgi_webdav_propfind_item_add(ub, slashed, strlen(entry)+1, stat_size, stat_mtime, mime_type, mime_type_len, NULL, 0, NULL, 0)) { free(slashed); goto end; } free(slashed); if (uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos)) goto end; // reset buffer; ub->pos = 0; } rados_objects_list_close(ctx_list); if (uwsgi_webdav_multistatus_close(ub)) goto end; uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos); end: uwsgi_buffer_destroy(ub); }
static int uwsgi_cache_request(struct wsgi_request *wsgi_req) { uint64_t vallen = 0; char *value; char *argv[3]; uint16_t argvs[3]; uint8_t argc = 0; // used for modifier2 17 struct uwsgi_cache_magic_context ucmc; struct uwsgi_cache *uc = NULL; switch(wsgi_req->uh->modifier2) { case 0: // get if (wsgi_req->uh->_pktsize > 0) { value = uwsgi_cache_magic_get(wsgi_req->buffer, wsgi_req->uh->_pktsize, &vallen, NULL, NULL); if (value) { wsgi_req->uh->_pktsize = vallen; if (uwsgi_response_write_body_do(wsgi_req, (char *)&wsgi_req->uh, 4)) { free(value) ; return -1;} uwsgi_response_write_body_do(wsgi_req, value, vallen); free(value); } } break; case 1: // set if (wsgi_req->uh->_pktsize > 0) { // max 3 items argc = 3; if (!uwsgi_parse_array(wsgi_req->buffer, wsgi_req->uh->_pktsize, argv, argvs, &argc)) { if (argc > 1) { uwsgi_cache_magic_set(argv[0], argvs[0], argv[1], argvs[1], 0, 0, NULL); } } } break; case 2: // del if (wsgi_req->uh->_pktsize > 0) { uwsgi_cache_magic_del(wsgi_req->buffer, wsgi_req->uh->_pktsize, NULL); } break; case 3: case 4: // dict if (wsgi_req->uh->_pktsize > 0) { uwsgi_hooked_parse(wsgi_req->buffer, wsgi_req->uh->_pktsize, cache_simple_command, (void *) wsgi_req); } break; case 5: // get (uwsgi + stream) if (wsgi_req->uh->_pktsize > 0) { value = uwsgi_cache_magic_get(wsgi_req->buffer, wsgi_req->uh->_pktsize, &vallen, NULL, NULL); if (value) { wsgi_req->uh->_pktsize = 0; wsgi_req->uh->modifier2 = 1; if (uwsgi_response_write_body_do(wsgi_req, (char *)&wsgi_req->uh, 4)) { free(value) ;return -1;} uwsgi_response_write_body_do(wsgi_req, value, vallen); free(value); } else { wsgi_req->uh->_pktsize = 0; wsgi_req->uh->modifier2 = 0; uwsgi_response_write_body_do(wsgi_req, (char *)&wsgi_req->uh, 4); free(value); } } break; case 6: // dump uc = uwsgi.caches; if (wsgi_req->uh->_pktsize > 0) { uc = uwsgi_cache_by_namelen(wsgi_req->buffer, wsgi_req->uh->_pktsize); } if (!uc) break; uwsgi_wlock(uc->lock); struct uwsgi_buffer *cache_dump = uwsgi_buffer_new(uwsgi.page_size + uc->filesize); cache_dump->pos = 4; if (uwsgi_buffer_append_keynum(cache_dump, "items", 5, uc->max_items)) { uwsgi_buffer_destroy(cache_dump); break; } if (uwsgi_buffer_append_keynum(cache_dump, "blocksize", 9, uc->blocksize)) { uwsgi_buffer_destroy(cache_dump); break; } if (uwsgi_buffer_set_uh(cache_dump, 111, 7)) { uwsgi_buffer_destroy(cache_dump); break; } if (uwsgi_buffer_append(cache_dump, (char *)uc->items, uc->filesize)) { uwsgi_buffer_destroy(cache_dump); break; } uwsgi_rwunlock(uc->lock); uwsgi_response_write_body_do(wsgi_req, cache_dump->buf, cache_dump->pos); uwsgi_buffer_destroy(cache_dump); break; case 17: if (wsgi_req->uh->_pktsize == 0) break; memset(&ucmc, 0, sizeof(struct uwsgi_cache_magic_context)); if (uwsgi_hooked_parse(wsgi_req->buffer, wsgi_req->uh->_pktsize, uwsgi_cache_magic_context_hook, &ucmc)) { break; } manage_magic_context(wsgi_req, &ucmc); break; default: break; } return UWSGI_OK; }
static int uwsgi_websockets_pong(struct wsgi_request *wsgi_req) { return uwsgi_response_write_body_do(wsgi_req, uwsgi.websockets_pong->buf, uwsgi.websockets_pong->pos); }
static int uwsgi_websocket_send_do(struct wsgi_request *wsgi_req, char *msg, size_t len, uint8_t opcode) { struct uwsgi_buffer *ub = uwsgi_websocket_message(wsgi_req, msg, len, opcode); if (!ub) return -1; return uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos); }
int uwsgi_response_subhandler_pump(struct wsgi_request *wsgi_req) { PyObject *pychunk; int i; char sc[4]; // ok its a yield if (!wsgi_req->async_placeholder) { if (PyDict_Check((PyObject *)wsgi_req->async_result)) { PyObject *status = PyDict_GetItemString((PyObject *)wsgi_req->async_result, "status"); if (!status) { uwsgi_log("invalid Pump response (status code).\n"); goto clear; } PyObject *headers = PyDict_GetItemString((PyObject *)wsgi_req->async_result, "headers"); if (!headers) { uwsgi_log("invalid Pump response (headers).\n"); goto clear; } wsgi_req->async_placeholder = PyDict_GetItemString((PyObject *)wsgi_req->async_result, "body"); if (!wsgi_req->async_placeholder) { uwsgi_log("invalid Pump response (body).\n"); goto clear; } // get the status code if (!PyInt_Check(status)) { uwsgi_log("invalid Pump response (status code).\n"); goto clear; } if (uwsgi_num2str2n(PyInt_AsLong(status), sc, 4) != 3) { uwsgi_log("invalid Pump response (status code).\n"); goto clear; } if (uwsgi_response_prepare_headers(wsgi_req, sc, 3)) { uwsgi_log("unable to prepare response headers\n"); } PyObject *hhkey, *hhvalue; #ifdef UWSGI_PYTHON_OLD int hhpos = 0; #else Py_ssize_t hhpos = 0; #endif while (PyDict_Next(headers, &hhpos, &hhkey, &hhvalue)) { if (!PyString_Check(hhkey)) continue; char *k = PyString_AsString(hhkey); size_t kl = PyString_Size(hhkey); k[0] = toupper((int) k[0]); if (PyList_Check(hhvalue)) { for(i=0;i<PyList_Size(hhvalue);i++) { PyObject *item = PyList_GetItem(hhvalue, i); if (PyString_Check(item)) { if (uwsgi_response_add_header(wsgi_req, k, kl, PyString_AsString(item), PyString_Size(item))) goto clear; } } } else if (PyString_Check(hhvalue)) { if (uwsgi_response_add_header(wsgi_req, k, kl, PyString_AsString(hhvalue), PyString_Size(hhvalue))) goto clear; } } Py_INCREF((PyObject *)wsgi_req->async_placeholder); if (PyString_Check((PyObject *)wsgi_req->async_placeholder)) { UWSGI_RELEASE_GIL uwsgi_response_write_body_do(wsgi_req, PyString_AsString(wsgi_req->async_placeholder), PyString_Size(wsgi_req->async_placeholder)); UWSGI_GET_GIL uwsgi_py_check_write_errors { uwsgi_py_write_exception(wsgi_req); } goto clear; } #ifdef PYTHREE else if ((wsgi_req->sendfile_fd = PyObject_AsFileDescriptor((PyObject *)wsgi_req->async_placeholder)) > -1) {
static int uwsgi_lua_request(struct wsgi_request *wsgi_req) { int i; const char *http, *http2; size_t slen, slen2; char *ptrbuf; lua_State *L = ulua.L[wsgi_req->async_id]; if (wsgi_req->async_status == UWSGI_AGAIN) { if ((i = lua_pcall(L, 0, 1, 0)) == 0) { if (lua_type(L, -1) == LUA_TSTRING) { http = lua_tolstring(L, -1, &slen); uwsgi_response_write_body_do(wsgi_req, (char *)http, slen); } lua_pop(L, 1); lua_pushvalue(L, -1); return UWSGI_AGAIN; } goto clear; } /* Standard WSAPI request */ if (!wsgi_req->uh->pktsize) { uwsgi_log( "Empty lua request. skip.\n"); return -1; } if (uwsgi_parse_vars(wsgi_req)) { return -1; } // put function in the stack //lua_getfield(L, LUA_GLOBALSINDEX, "run"); lua_pushvalue(L, -1); // put cgi vars in the stack lua_newtable(L); lua_pushstring(L, ""); lua_setfield(L, -2, "CONTENT_TYPE"); for(i=0;i<wsgi_req->var_cnt;i++) { lua_pushlstring(L, (char *)wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len); // transform it in a valid c string TODO this is ugly ptrbuf = wsgi_req->hvec[i].iov_base+wsgi_req->hvec[i].iov_len; *ptrbuf = 0; lua_setfield(L, -2, (char *)wsgi_req->hvec[i].iov_base); i++; } // put "input" table lua_newtable(L); lua_pushcfunction(L, uwsgi_lua_input); lua_setfield(L, -2, "read"); lua_setfield(L, -2, "input"); #ifdef UWSGI_DEBUG uwsgi_log("stack pos %d\n", lua_gettop(L)); #endif // call function i = lua_pcall(L, 1, 3, 0); if (i != 0) { uwsgi_log("%s\n", lua_tostring(L, -1)); lua_pop(L, 1); lua_pushvalue(L, -1); goto clear; } //uwsgi_log("%d %s %s %s\n",i,lua_typename(L, lua_type(L, -3)), lua_typename(L, lua_type(L, -2)) , lua_typename(L, lua_type(L, -1))); // send status if (lua_type(L, -3) == LUA_TSTRING || lua_type(L, -3) == LUA_TNUMBER) { http = lua_tolstring(L, -3, &slen); uwsgi_response_prepare_headers(wsgi_req, (char *) http, slen); } else { uwsgi_log("[uwsgi-lua] invalid response status !!!\n"); // let's continue } // send headers lua_pushnil(L); while(lua_next(L, -3) != 0) { http = lua_tolstring(L, -2, &slen); http2 = lua_tolstring(L, -1, &slen2); uwsgi_response_add_header(wsgi_req, (char *) http, slen, (char *) http2, slen2); lua_pop(L, 1); } // send body with coroutine lua_pushvalue(L, -1); while ( (i = lua_pcall(L, 0, 1, 0)) == 0) { if (lua_type(L, -1) == LUA_TSTRING) { http = lua_tolstring(L, -1, &slen); uwsgi_response_write_body_do(wsgi_req, (char *)http, slen); } lua_pop(L, 1); lua_pushvalue(L, -1); if (uwsgi.async > 1) { return UWSGI_AGAIN; } } clear: lua_pop(L, 4); // set frequency lua_gc(L, LUA_GCCOLLECT, 0); return UWSGI_OK; }
static int uwsgi_cgi_parse(struct wsgi_request *wsgi_req, int fd, char *buf, size_t blen) { size_t i; size_t header_size = 0; int status_sent = 0; size_t remains = blen; char *ptr = buf; size_t len = 0; while(remains > 0) { ssize_t rlen = uwsgi_read_true_nb(fd, ptr, remains, uc.timeout); if (rlen < 0) { if (!errno) return 1; return -1; } // timed out if (rlen == 0) return -1; remains -= rlen; len += rlen; ptr += rlen; // Search for Status/Location headers if (!status_sent) { status_sent = uwsgi_cgi_check_status(wsgi_req, buf, len); if (status_sent < 0) return -1; // need more data ? if (status_sent == 0) continue; } // send headers char *key = buf; char *value = NULL; for(i=0;i<len;i++) { // end of a line if (buf[i] == '\n') { // end of headers if (key == NULL) { i++; goto send_body; } // invalid header else if (value == NULL) { return -1; } header_size = (buf+i) - key; // security check if (buf+i > buf) { if ((buf[i-1]) == '\r') { header_size--; } } #ifdef UWSGI_DEBUG uwsgi_log("found CGI header: %.*s\n", header_size, key); #endif // Ignore "Status: NNN" header if (header_size >= 11) { if (!strncasecmp("Status: ", key, 8)) { key = NULL; value = NULL; continue; } } uwsgi_response_add_header(wsgi_req, NULL, 0, key, header_size); key = NULL; value = NULL; } else if (buf[i] == ':') { value = buf+i; } else if (buf[i] != '\r') { if (key == NULL) { key = buf + i; } } } } return -1; send_body: if (len-i > 0) { uwsgi_response_write_body_do(wsgi_req, buf+i, len-i); } return 0; }
static int uwsgi_request_xslt(struct wsgi_request *wsgi_req) { char *xmlfile = NULL; char *output = NULL; int output_rlen = 0; char filename[PATH_MAX+1]; size_t filename_len = 0; char stylesheet[PATH_MAX+1]; size_t stylesheet_len = 0; char *params = NULL; if (uwsgi_parse_vars(wsgi_req)) { return -1; } // set default values if (!uxslt.content_type_len) { if (!uxslt.content_type) { uxslt.content_type = "text/html"; } uxslt.content_type_len = strlen(uxslt.content_type); } struct uwsgi_string_list *usl = uxslt.docroot; // first check for static docroots if (usl) { while(usl) { xmlfile = uwsgi_concat3n(usl->value, usl->len, "/", 1, wsgi_req->path_info, wsgi_req->path_info_len); if (uwsgi_is_file(xmlfile)) { break; } free(xmlfile); xmlfile = NULL; usl = usl->next; } } // fallback to DOCUMENT_ROOT else { if (wsgi_req->document_root_len == 0) { uwsgi_403(wsgi_req); return UWSGI_OK; } xmlfile = uwsgi_concat3n(wsgi_req->document_root, wsgi_req->document_root_len, "/", 1, wsgi_req->path_info, wsgi_req->path_info_len); } if (!xmlfile) { uwsgi_404(wsgi_req); return UWSGI_OK; } // we have the full path, check if it is valid if (!uwsgi_expand_path(xmlfile, strlen(xmlfile), filename)) { free(xmlfile); uwsgi_404(wsgi_req); return UWSGI_OK; } free(xmlfile); if (!uwsgi_is_file(filename)) { uwsgi_403(wsgi_req); return UWSGI_OK; } filename_len = strlen(filename); // now search for the xslt file int found = 0; // first check for specific vars usl = uxslt.var; while(usl) { uint16_t rlen; char *value = uwsgi_get_var(wsgi_req, usl->value, usl->len, &rlen); if (value) { memcpy(stylesheet, value, rlen); stylesheet[rlen] = 0; stylesheet_len = rlen; found = 1; break; } usl = usl->next; } if (found) goto apply; // then check for custom extensions if (uxslt.ext) { usl = uxslt.ext; while(usl) { char *tmp_path = uwsgi_concat2n(filename, filename_len, usl->value, usl->len); if (uwsgi_is_file(tmp_path)) { stylesheet_len = filename_len + usl->len; memcpy(stylesheet, tmp_path, stylesheet_len); stylesheet[stylesheet_len] = 0; free(tmp_path); found = 1; break; } free(tmp_path); usl = usl->next; } } // use default extensions .xsl/.xslt else { char *tmp_path = uwsgi_concat2n(filename, filename_len, ".xsl", 4); if (uwsgi_is_file(tmp_path)) { stylesheet_len = filename_len + 4; memcpy(stylesheet, tmp_path, stylesheet_len); stylesheet[stylesheet_len] = 0; free(tmp_path); goto apply; } free(tmp_path); tmp_path = uwsgi_concat2n(filename, filename_len, ".xslt", 5); if (uwsgi_is_file(tmp_path)) { stylesheet_len = filename_len + 5; memcpy(stylesheet, tmp_path, stylesheet_len); stylesheet[stylesheet_len] = 0; found = 1; } free(tmp_path); } if (found) goto apply; // finally check for static stylesheets usl = uxslt.stylesheet; while(usl) { if (uwsgi_is_file(usl->value)) { memcpy(stylesheet, usl->value, usl->len); stylesheet_len = usl->len; stylesheet[stylesheet_len] = 0; found = 1; break; } usl = usl->next; } if (found) goto apply; uwsgi_404(wsgi_req); return UWSGI_OK; apply: if (wsgi_req->query_string_len > 0) { params = uwsgi_concat2n(wsgi_req->query_string, wsgi_req->query_string_len, "", 0); } // we have both the file and the stylesheet, let's run the engine output = uwsgi_xslt_apply(filename, stylesheet, params, &output_rlen); if (params) free(params); if (!output) { uwsgi_500(wsgi_req); return UWSGI_OK; } // prepare headers if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) { uwsgi_500(wsgi_req); goto end; } // content_length if (uwsgi_response_add_content_length(wsgi_req, output_rlen)) { uwsgi_500(wsgi_req); goto end; } // content_type if (uwsgi_response_add_content_type(wsgi_req, uxslt.content_type, uxslt.content_type_len)) { uwsgi_500(wsgi_req); goto end; } uwsgi_response_write_body_do(wsgi_req, output, output_rlen); end: xmlFree(output); return UWSGI_OK; }
int uwsgi_exceptions_catch(struct wsgi_request *wsgi_req) { if (uwsgi_response_prepare_headers(wsgi_req, "500 Internal Server Error", 25)) { return -1; } if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10)) { return -1; } struct uwsgi_buffer *ub = uwsgi_buffer_new(4096); if (uwsgi_buffer_append(ub, "uWSGI exceptions catcher for \"", 30)) goto error; if (uwsgi_buffer_append(ub, wsgi_req->method, wsgi_req->method_len)) goto error; if (uwsgi_buffer_append(ub, " ", 1)) goto error; if (uwsgi_buffer_append(ub, wsgi_req->uri, wsgi_req->uri_len)) goto error; if (uwsgi_buffer_append(ub, "\" (request plugin: \"", 20)) goto error; if (uwsgi_buffer_append(ub, (char *) uwsgi.p[wsgi_req->uh->modifier1]->name, strlen(uwsgi.p[wsgi_req->uh->modifier1]->name))) goto error; if (uwsgi_buffer_append(ub, "\", modifier1: ", 14 )) goto error; if (uwsgi_buffer_num64(ub, wsgi_req->uh->modifier1)) goto error; if (uwsgi_buffer_append(ub, ")\n\n", 3)) goto error; if (uwsgi_buffer_append(ub, "Exception: ", 11)) goto error; if (uwsgi.p[wsgi_req->uh->modifier1]->exception_repr) { struct uwsgi_buffer *ub_exc_repr = uwsgi.p[wsgi_req->uh->modifier1]->exception_repr(wsgi_req); if (ub_exc_repr) { if (uwsgi_buffer_append(ub, ub_exc_repr->buf, ub_exc_repr->pos)) { uwsgi_buffer_destroy(ub_exc_repr); goto error; } uwsgi_buffer_destroy(ub_exc_repr); } else { goto notavail3; } } else { notavail3: if (uwsgi_buffer_append(ub, "-Not available-", 15)) goto error; } if (uwsgi_buffer_append(ub, "\n\n", 2)) goto error; if (uwsgi_buffer_append(ub, "Exception class: ", 17)) goto error; if (uwsgi.p[wsgi_req->uh->modifier1]->exception_class) { struct uwsgi_buffer *ub_exc_class = uwsgi.p[wsgi_req->uh->modifier1]->exception_class(wsgi_req); if (ub_exc_class) { if (uwsgi_buffer_append(ub, ub_exc_class->buf, ub_exc_class->pos)) { uwsgi_buffer_destroy(ub_exc_class); goto error; } uwsgi_buffer_destroy(ub_exc_class); } else { goto notavail; } } else { notavail: if (uwsgi_buffer_append(ub, "-Not available-", 15)) goto error; } if (uwsgi_buffer_append(ub, "\n\n", 2)) goto error; if (uwsgi_buffer_append(ub, "Exception message: ", 19)) goto error; if (uwsgi.p[wsgi_req->uh->modifier1]->exception_msg) { struct uwsgi_buffer *ub_exc_msg = uwsgi.p[wsgi_req->uh->modifier1]->exception_msg(wsgi_req); if (ub_exc_msg) { if (uwsgi_buffer_append(ub, ub_exc_msg->buf, ub_exc_msg->pos)) { uwsgi_buffer_destroy(ub_exc_msg); goto error; } uwsgi_buffer_destroy(ub_exc_msg); } else { goto notavail2; } } else { notavail2: if (uwsgi_buffer_append(ub, "-Not available-", 15)) goto error; } if (uwsgi_buffer_append(ub, "\n\n", 2)) goto error; if (uwsgi_buffer_append(ub, "Backtrace:\n", 11)) goto error; if (uwsgi.p[wsgi_req->uh->modifier1]->backtrace) { struct uwsgi_buffer *ub_exc_bt = uwsgi.p[wsgi_req->uh->modifier1]->backtrace(wsgi_req); if (ub_exc_bt) { struct uwsgi_buffer *parsed_bt = uwsgi_buffer_new(4096); if (uwsgi_hooked_parse_array(ub_exc_bt->buf, ub_exc_bt->pos, append_backtrace_to_ubuf, parsed_bt)) { uwsgi_buffer_destroy(ub_exc_bt); uwsgi_buffer_destroy(parsed_bt); goto error; } uwsgi_buffer_destroy(ub_exc_bt); if (uwsgi_buffer_append(ub, parsed_bt->buf, parsed_bt->pos)) { uwsgi_buffer_destroy(parsed_bt); goto error; } uwsgi_buffer_destroy(parsed_bt); } else { goto notavail4; } } else { notavail4: if (uwsgi_buffer_append(ub, "-Not available-", 15)) goto error; } if (uwsgi_buffer_append(ub, "\n\n", 2)) goto error; if (uwsgi_hooked_parse(wsgi_req->buffer, wsgi_req->uh->pktsize, append_vars_to_ubuf, ub)) { goto error; } if (uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos)) { goto error; } uwsgi_buffer_destroy(ub); return 0; error: uwsgi_buffer_destroy(ub); return -1; }
static int uwsgi_routing_func_xmldir(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){ char **subject; uint16_t *subject_len; char *dirname; struct uwsgi_buffer *ub; char *name = NULL; char *path = NULL; int i; int n; struct dirent **tasklist; xmlDoc *rdoc; xmlNode *rtree; xmlNodePtr entrynode; char *path_info = NULL; struct stat sb; size_t sizebuf_len; char *sizebuf; char timebuf[20]; int xlen = 0; subject = (char **) (((char *)(wsgi_req))+ur->subject); subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub) { uwsgi_500(wsgi_req); return UWSGI_ROUTE_BREAK; } dirname = ub->buf; path_info = uwsgi_concat2n(wsgi_req->path_info, wsgi_req->path_info_len, "", 1); n = scandir(dirname, &tasklist, 0, alphasort); if (n < 0) { uwsgi_404(wsgi_req); goto out; } rdoc = xmlNewDoc(BAD_CAST "1.0"); rtree = xmlNewNode(NULL, BAD_CAST "index"); xmlNewProp(rtree, BAD_CAST "path", BAD_CAST path_info); xmlDocSetRootElement(rdoc, rtree); for(i = 0; i < n; i++) { if ((strcmp(tasklist[i]->d_name, ".") == 0) || (strcmp(tasklist[i]->d_name, "..") == 0)) { goto next_entry; } path = uwsgi_concat3(dirname, "/", tasklist[i]->d_name); if (lstat(path, &sb) == -1) { goto next_entry; } name = to_utf8(conf.codeset, tasklist[i]->d_name); if (name == NULL) { goto next_entry; } if (S_ISDIR(sb.st_mode)) { entrynode = xmlNewTextChild(rtree, NULL, BAD_CAST "directory", BAD_CAST name); } else if (S_ISREG(sb.st_mode)) { entrynode = xmlNewTextChild(rtree, NULL, BAD_CAST "file", BAD_CAST name); } else { /* skip everything but directories and regular files */ goto next_entry; } sizebuf_len = snprintf(NULL, 0, "%jd", (intmax_t) sb.st_size); sizebuf = uwsgi_malloc(sizebuf_len + 1); snprintf(sizebuf, sizebuf_len + 1, "%jd", (intmax_t) sb.st_size); xmlNewProp(entrynode, BAD_CAST "size", BAD_CAST sizebuf); free(sizebuf); strftime(timebuf, sizeof (timebuf), "%Y-%m-%dT%H:%M:%S", localtime(&sb.st_mtime)); xmlNewProp(entrynode, BAD_CAST "mtime", BAD_CAST timebuf); next_entry: free(path); path = NULL; free(tasklist[i]); free(name); name = NULL; } free(tasklist); xmlChar *xmlbuf; xmlDocDumpFormatMemory(rdoc, &xmlbuf, &xlen, 1); uwsgi_response_prepare_headers(wsgi_req,"200 OK", 6); uwsgi_response_write_body_do(wsgi_req, (char *) xmlbuf, xlen); xmlFreeDoc(rdoc); xmlFree(xmlbuf); out: uwsgi_buffer_destroy(ub); free(path_info); return UWSGI_ROUTE_BREAK; }
static int uwsgi_routing_func_memcached(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){ // this is the buffer for the memcached response char buf[MEMCACHED_BUFSIZE]; size_t i; char last_char = 0; struct uwsgi_router_memcached_conf *urmc = (struct uwsgi_router_memcached_conf *) ur->data2; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub_key = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urmc->key, urmc->key_len); if (!ub_key) return UWSGI_ROUTE_BREAK; int fd = uwsgi_connect(urmc->addr, 0, 1); if (fd < 0) { uwsgi_buffer_destroy(ub_key) ; goto end; } // wait for connection; int ret = uwsgi.wait_write_hook(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]); if (ret <= 0) { uwsgi_buffer_destroy(ub_key) ; close(fd); goto end; } // build the request and send it char *cmd = uwsgi_concat3n("get ", 4, ub_key->buf, ub_key->pos, "\r\n", 2); if (uwsgi_write_true_nb(fd, cmd, 6+ub_key->pos, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) { uwsgi_buffer_destroy(ub_key); free(cmd); close(fd); goto end; } uwsgi_buffer_destroy(ub_key); free(cmd); // ok, start reading the response... // first we need to get a full line; size_t found = 0; size_t pos = 0; for(;;) { ssize_t len = read(fd, buf + pos, MEMCACHED_BUFSIZE - pos); if (len > 0) { pos += len; goto read; } if (len < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) goto wait; } close(fd); goto end; wait: ret = uwsgi.wait_read_hook(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]); // when we have a chunk try to read the first line if (ret > 0) { len = read(fd, buf + pos, MEMCACHED_BUFSIZE - pos); if (len > 0) { pos += len; goto read; } } close(fd); goto end; read: for(i=0;i<pos;i++) { if (last_char == '\r' && buf[i] == '\n') { found = i-1; break; } last_char = buf[i]; } if (found) break; } // ok parse the first line size_t response_size = memcached_firstline_parse(buf, found); if (response_size == 0) { close(fd); goto end; } if (urmc->type_num == 1) { if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) { close(fd); goto end; } if (uwsgi_response_add_content_type(wsgi_req, urmc->content_type, urmc->content_type_len)) { close(fd); goto end; } if (uwsgi_response_add_content_length(wsgi_req, response_size)) { close(fd); goto end; } } size_t remains = pos-(found+2); if (remains >= response_size) { uwsgi_response_write_body_do(wsgi_req, buf+found+2, response_size); close(fd); goto end; } // send what we have if (uwsgi_response_write_body_do(wsgi_req, buf+found+2, remains)) { close(fd); goto end; } // and now start reading til the output is consumed response_size -= remains; while(response_size > 0) { ssize_t len = read(fd, buf, UMIN(MEMCACHED_BUFSIZE, response_size)); if (len > 0) goto write; if (len < 0) { if (errno == EAGAIN || errno == EWOULDBLOCK || errno == EINPROGRESS) goto wait2; } goto error; wait2: ret = uwsgi.wait_read_hook(fd, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT]); if (ret > 0) { len = read(fd, buf, UMIN(MEMCACHED_BUFSIZE, response_size)); if (len > 0) goto write; } goto error; write: if (uwsgi_response_write_body_do(wsgi_req, buf, len)) { goto error; } response_size -= len; } close(fd); return UWSGI_ROUTE_BREAK; error: close(fd); end: if (ur->custom) return UWSGI_ROUTE_NEXT; return UWSGI_ROUTE_BREAK; }