static nxweb_result download_on_request(nxweb_http_server_connection* conn, nxweb_http_request* req, nxweb_http_response* resp) { nxweb_parse_request_parameters( req, 0 ); const char *name_space = nx_simple_map_get_nocase( req->parameters, "namespace" ); char * url = malloc(strlen(req->path_info)+1); if (!url) {return NXWEB_ERROR;} strcpy(url, req->path_info); url[strlen(req->path_info)] = '\0'; nxweb_url_decode( url, 0 ); char *fname = url, *temp; while (temp = strstr(fname, "/")) {fname = temp + 1;} char *strip_args = strstr(fname, "?"); int fname_len = strip_args ? (strip_args - fname) : strlen(fname); char fname_with_space[1024] = {0}; if ( strlen(url) > sizeof(fname_with_space)-1 ) { char err_msg[1024] = {0}; snprintf( err_msg, sizeof(err_msg)-1, "<html><body>File not found<br/>namespace:%s<br/>filename:%.*s</body></html>", name_space, fname_len, fname ); nxweb_send_http_error(resp, 404, err_msg); resp->keep_alive=0; free(url); return NXWEB_MISS; } if( name_space ) {sprintf( fname_with_space, "%s:/", name_space);} else {strcpy( fname_with_space, ":/" );} strncat( fname_with_space, fname, fname_len ); size_t file_size = 0; char *pfile_data = kcdbget( g_kcdb, fname_with_space, strlen(fname_with_space), &file_size ); if ( pfile_data == NULL ) { char err_msg[1024] = {0}; snprintf( err_msg, sizeof(err_msg)-1, "<html><body>File not found<br/>namespace:%s<br/>filename:%.*s</body></html>", name_space, fname_len, fname ); nxweb_send_http_error(resp, 404, err_msg); resp->keep_alive=0; free(url); return NXWEB_MISS; } KC_DATA *ptmp = nxb_alloc_obj(req->nxb, sizeof(KC_DATA)); nxweb_set_request_data(req, UPLOAD_HANDLER_KEY, (nxe_data)(void *)ptmp, upload_request_data_finalize); ptmp->data_ptr = pfile_data; nxweb_send_data( resp, pfile_data + RECORD_HEADER_LEN, file_size - RECORD_HEADER_LEN, "application/octet-stream" ); free(url); return NXWEB_OK; }
static inline nxweb_result invoke_request_handler(nxweb_http_server_connection* conn, nxweb_http_request* req, nxweb_http_response* resp, nxweb_handler* h, nxweb_handler_flags flags) { if (conn->connection_closing) return; // do not process if already closing if (flags&NXWEB_PARSE_PARAMETERS) nxweb_parse_request_parameters(req, 1); // !!(flags&NXWEB_PRESERVE_URI) if (flags&NXWEB_PARSE_COOKIES) nxweb_parse_request_cookies(req); nxb_start_stream(req->nxb); nxweb_result res=NXWEB_OK; if (h->on_request) { if (flags&NXWEB_INWORKER) { nxw_worker* w=nxw_get_worker(&conn->tdata->workers_factory); if (!w) { nxweb_send_http_error(resp, 503, "Service Unavailable"); nxweb_start_sending_response(conn, resp); return NXWEB_ERROR; } nxe_subscribe(conn->tdata->loop, &w->complete_efs.data_notify, &conn->worker_complete); nxw_start_worker(w, invoke_request_handler_in_worker, conn, &conn->worker_job_done); conn->in_worker=1; } else { res=h->on_request(conn, req, resp); nxd_http_server_proto_finish_response(resp); if (res!=NXWEB_ASYNC) nxweb_start_sending_response(conn, resp); } } return res; }
static nxweb_result python_on_post_data(nxweb_http_server_connection* conn, nxweb_http_request* req, nxweb_http_response* resp) { if (req->content_length>0 && req->content_length<NXWEB_MAX_REQUEST_BODY_SIZE) { // fallback to default in-memory buffering return NXWEB_NEXT; } if (!conn->handler->dir) { nxweb_log_warning("python handler temp upload file dir not set => skipping file buffering for %s", req->uri); return NXWEB_NEXT; } nxe_ssize_t upload_size_limit=conn->handler->size? conn->handler->size : NXWEB_MAX_PYTHON_UPLOAD_SIZE; if (req->content_length > upload_size_limit) { nxweb_send_http_error(resp, 413, "Request Entity Too Large"); resp->keep_alive=0; // close connection nxweb_start_sending_response(conn, resp); return NXWEB_OK; } char* fname_template=nxb_alloc_obj(req->nxb, strlen(conn->handler->dir)+sizeof("/py_upload_tmp_XXXXXX")+1); strcat(strcpy(fname_template, conn->handler->dir), "/py_upload_tmp_XXXXXX"); if (nxweb_mkpath(fname_template, 0755)==-1) { nxweb_log_error("can't create path to temp upload file %s; check permissions", fname_template); nxweb_send_http_error(resp, 500, "Internal Server Error"); resp->keep_alive=0; // close connection nxweb_start_sending_response(conn, resp); return NXWEB_OK; } int fd=mkstemp(fname_template); if (fd==-1) { nxweb_log_error("can't open (mkstemp()) temp upload file for %s", req->uri); nxweb_send_http_error(resp, 500, "Internal Server Error"); resp->keep_alive=0; // close connection nxweb_start_sending_response(conn, resp); return NXWEB_OK; } unlink(fname_template); // auto-delete on close() nxd_fwbuffer* fwb=nxb_alloc_obj(req->nxb, sizeof(nxd_fwbuffer)); nxweb_set_request_data(req, PYTHON_HANDLER_KEY, (nxe_data)(void*)fwb, python_request_data_finalize); nxd_fwbuffer_init(fwb, fd, upload_size_limit); conn->hsp.cls->connect_request_body_out(&conn->hsp, &fwb->data_in); conn->hsp.cls->start_receiving_request_body(&conn->hsp); return NXWEB_OK; }
static nxweb_result delete_on_request( nxweb_http_server_connection* conn, nxweb_http_request* req, nxweb_http_response* resp) { nxweb_set_response_content_type(resp, "text/plain"); nxweb_parse_request_parameters(req, 0); const char *name_space = nx_simple_map_get_nocase(req->parameters, "namespace"); char * url = malloc(strlen(req->path_info)+1); if (!url) { nxweb_send_http_error(resp, 500, "Please retry"); resp->keep_alive=0; return NXWEB_ERROR; } strcpy(url, req->path_info); url[strlen(req->path_info)] = '\0'; nxweb_url_decode(url, 0); char *fname = url, *temp; while (temp = strstr(fname, "/")) {fname = temp + 1;} char *strip_args = strstr(fname, "?"); int fname_len = strip_args?strip_args-fname:strlen(fname); char fname_with_space[1024]= {0}; if (strlen(url) > sizeof(fname_with_space)-1) { nxweb_send_http_error(resp, 414, "Request URI Too Long"); resp->keep_alive=0; free(url); return NXWEB_MISS; } if (name_space) {sprintf( fname_with_space, "%s:/", name_space);} else {strcpy(fname_with_space, ":/");} strncat(fname_with_space, fname, fname_len); kcdbremove(g_kcdb, fname_with_space, strlen( fname_with_space)); nxweb_response_printf(resp, "OK\n"); free(url); return NXWEB_OK; }
/////////////// clean ////////////////////// static nxweb_result clean_on_request( nxweb_http_server_connection* conn, nxweb_http_request* req, nxweb_http_response* resp) { if (strlen(req->path_info) <= 1 || strlen(req->path_info) >= 4 ) { nxweb_send_http_error(resp, 403, "NUMBER error!\nExample:\nhttp://host:port/clean/24"); resp->keep_alive=0; return NXWEB_ERROR; } char tmp[8] = {0}; strcpy(tmp, (req->path_info) +1); int interval_hour = atoi(tmp); if (interval_hour < 0 || interval_hour > 99) { nxweb_send_http_error(resp, 403, "NUMBER error!\nExample:\nhttp://host:port/clean/24"); resp->keep_alive=0; return NXWEB_ERROR; } WipeData(interval_hour); nxweb_response_printf(resp, "OK"); return NXWEB_OK; }
static void fail_proxy_request(nxweb_http_proxy_request_data* rdata) { nxweb_log_debug("fail_proxy_request"); nxweb_http_server_connection* conn=rdata->conn; if (rdata->response_sending_started) { nxweb_http_server_connection_finalize(conn, 0); } else { nxweb_http_response* resp=&conn->hsp._resp; nxweb_send_http_error(resp, 504, "Gateway Timeout"); nxweb_start_sending_response(conn, resp); rdata->response_sending_started=1; rdata->proxy_request_complete=1; // ignore further backend errors } }
static nxweb_result default_on_headers(nxweb_http_server_connection* conn, nxweb_http_request* req, nxweb_http_response* resp) { nxweb_send_http_error(resp, 404, "Not Found"); return NXWEB_ERROR; }
static void nxweb_http_server_connection_events_sub_on_message(nxe_subscriber* sub, nxe_publisher* pub, nxe_data data) { nxweb_http_server_connection* conn=(nxweb_http_server_connection*)((char*)sub-offsetof(nxweb_http_server_connection, events_sub)); //nxe_loop* loop=sub->super.loop; nxweb_http_request* req=&conn->hsp.req; nxweb_http_response* resp=&conn->hsp._resp; if (data.i==NXD_HSP_REQUEST_RECEIVED) { assert(nxweb_server_config.request_dispatcher); assert(nxweb_server_config.access_log_on_request_received); nxweb_log_debug("nxweb_http_server_connection_events_sub_on_message NXD_HSP_REQUEST_RECEIVED"); req->received_time=nxweb_get_loop_time(conn); nxweb_server_config.access_log_on_request_received(conn, req); nxweb_server_config.request_dispatcher(conn, req, resp); if (!conn->handler) conn->handler=&nxweb_default_handler; if (conn->hsp.state==HSP_SENDING_HEADERS || resp->run_filter_idx) return; // one of callbacks has already started sending response nxweb_handler* h=conn->handler; nxweb_handler_flags flags=h->flags; if (flags&_NXWEB_HANDLE_MASK) { if (((!(flags&NXWEB_HANDLE_GET) || !req->get_method) && (!(flags&NXWEB_HANDLE_POST) || !req->post_method) && (!(flags&NXWEB_HANDLE_OTHER) || !req->other_method)) || (req->content_length && !(flags&(NXWEB_HANDLE_POST|NXWEB_ACCEPT_CONTENT)))) { nxweb_send_http_error(resp, 405, "Method Not Allowed"); if (req->content_length) resp->keep_alive=0; // close connection if there is body pending nxweb_start_sending_response(conn, resp); return; } } if (h->on_headers) { if (NXWEB_OK!=h->on_headers(conn, req, resp)) { // request processing terminated by http error response if (req->content_length) resp->keep_alive=0; // close connection if there is body pending nxweb_start_sending_response(conn, resp); return; } } if (conn->hsp.state==HSP_SENDING_HEADERS) return; // one of callbacks has already started sending headers if (req->content_length) { if (h->on_post_data) h->on_post_data(conn, req, resp); if (conn->hsp.state!=HSP_SENDING_HEADERS && !conn->hsp.cls->get_request_body_out_pair(&conn->hsp)) { // stream still not connected if (req->content_length>NXWEB_MAX_REQUEST_BODY_SIZE) { nxweb_send_http_error(resp, 413, "Request Entity Too Large"); resp->keep_alive=0; // close connection nxweb_start_sending_response(conn, resp); return; } nxe_loop* loop=conn->tdata->loop; nxd_ibuffer_init(&conn->ib, conn->hsp.nxb, req->content_length>0? req->content_length+1 : NXWEB_MAX_REQUEST_BODY_SIZE); conn->hsp.cls->connect_request_body_out(&conn->hsp, &conn->ib.data_in); conn->hsp.cls->start_receiving_request_body(&conn->hsp); req->buffering_to_memory=1; } } else { invoke_request_handler(conn, req, resp, h, flags); } } else if (data.i==NXD_HSP_REQUEST_BODY_RECEIVED) { assert(conn->handler); nxweb_log_debug("nxweb_http_server_connection_events_sub_on_message NXD_HSP_REQUEST_BODY_RECEIVED"); nxweb_handler* h=conn->handler; nxweb_handler_flags flags=h->flags; if (h->on_post_data_complete) h->on_post_data_complete(conn, req, resp); if (req->buffering_to_memory && conn->hsp.cls->get_request_body_out_pair(&conn->hsp)==&conn->ib.data_in) { int size; req->content=nxd_ibuffer_get_result(&conn->ib, &size); assert(req->content_received==size); } invoke_request_handler(conn, req, resp, h, flags); } else if (data.i==NXD_HSP_REQUEST_COMPLETE) { nxweb_log_debug("nxweb_http_server_connection_events_sub_on_message NXD_HSP_REQUEST_COMPLETE"); conn->hsp.cls->request_cleanup(sub->super.loop, &conn->hsp); assert(!conn->handler); } else if (data.i==NXD_HSP_RESPONSE_READY) { nxweb_log_debug("nxweb_http_server_connection_events_sub_on_message NXD_HSP_RESPONSE_READY"); // this must be subrequest assert(!conn->response_ready); // make sure this happens only once conn->response_ready=1; if (conn->on_response_ready) conn->on_response_ready(conn, conn->on_response_ready_data); } else if (data.i<0) { nxweb_log_debug("nxweb_http_server_connection_events_sub_on_message data.i=%d", data.i); if (conn->handler && conn->handler->on_error) conn->handler->on_error(conn, req, resp); if (conn->hsp.headers_bytes_received) { nxweb_log_warning("conn %p error: i=%d errno=%d state=%d rc=%d br=%d", conn, data.i, errno, conn->hsp.state, conn->hsp.request_count, conn->hsp.headers_bytes_received); } int good=(!conn->hsp.headers_bytes_received && (data.i==NXE_RDHUP || data.i==NXE_HUP || data.i==NXE_RDCLOSED)); // normal close nxweb_http_server_connection_finalize(conn, good); // bad connections get RST'd } }
nxweb_result nxweb_cache_store_response(nxweb_http_server_connection* conn, nxweb_http_response* resp) { nxe_time_t loop_time=nxweb_get_loop_time(conn); if (!resp->status_code) resp->status_code=200; if (resp->status_code==200 && resp->sendfile_path // only cache content from files && resp->content_length>=0 && resp->content_length<=NXWEB_MAX_CACHED_ITEM_SIZE // must be small && resp->sendfile_offset==0 && resp->sendfile_end==resp->content_length // whole file only && resp->sendfile_end>=resp->sendfile_info.st_size // st_size could be zero if not initialized && alignhash_size(_nxweb_cache)<NXWEB_MAX_CACHED_ITEMS+16) { const char* fpath=resp->sendfile_path; const char* key=resp->cache_key; if (nxweb_cache_try(conn, resp, key, 0, resp->last_modified)!=NXWEB_MISS) return NXWEB_OK; nxweb_cache_rec* rec=nx_calloc(sizeof(nxweb_cache_rec)+resp->content_length+1+strlen(key)+1); rec->expires_time=loop_time+NXWEB_DEFAULT_CACHED_TIME; rec->last_modified=resp->last_modified; rec->content_type=resp->content_type; // assume content_type and content_charset come rec->content_charset=resp->content_charset; // from statically allocated memory, which won't go away rec->content_length=resp->content_length; rec->gzip_encoded=resp->gzip_encoded; char* ptr=((char*)rec)+offsetof(nxweb_cache_rec, content); int fd; if ((fd=open(fpath, O_RDONLY))<0 || read(fd, ptr, resp->content_length)!=resp->content_length) { if (fd>0) close(fd); nx_free(rec); nxweb_log_error("nxweb_cache_file_store_and_send(): [%s] stat() was OK, but open/read() failed", fpath); nxweb_send_http_error(resp, 500, "Internal Server Error"); return NXWEB_ERROR; } close(fd); resp->content=ptr; ptr+=resp->content_length; *ptr++='\0'; strcpy(ptr, key); key=ptr; int ret=0; ah_iter_t ci; pthread_mutex_lock(&_nxweb_cache_mutex); ci=alignhash_set(nxweb_cache, _nxweb_cache, key, &ret); if (ci!=alignhash_end(_nxweb_cache)) { if (ret!=AH_INS_ERR) { alignhash_value(_nxweb_cache, ci)=rec; cache_rec_link(rec); rec->ref_count++; cache_check_size(); pthread_mutex_unlock(&_nxweb_cache_mutex); nxweb_log_info("memcached %s", key); conn->hsp.req_data=rec; assert(!conn->hsp.req_finalize); conn->hsp.req_finalize=cache_rec_unref; //nxweb_start_sending_response(conn, resp); return NXWEB_OK; } else { // AH_INS_ERR => key already exists (added by other thread) nx_free(rec); rec=alignhash_value(_nxweb_cache, ci); resp->content_length=rec->content_length; resp->content=rec->content; resp->content_type=rec->content_type; resp->content_charset=rec->content_charset; resp->last_modified=rec->last_modified; resp->gzip_encoded=rec->gzip_encoded; rec->ref_count++; pthread_mutex_unlock(&_nxweb_cache_mutex); conn->hsp.req_data=rec; assert(!conn->hsp.req_finalize); conn->hsp.req_finalize=cache_rec_unref; //nxweb_start_sending_response(conn, resp); return NXWEB_OK; } } pthread_mutex_unlock(&_nxweb_cache_mutex); nx_free(rec); } return NXWEB_OK; }
static nxweb_result python_on_request(nxweb_http_server_connection* conn, nxweb_http_request* req, nxweb_http_response* resp) { nxb_buffer* nxb=req->nxb; nxweb_handler* handler=conn->handler; const char* request_uri=req->uri; char* query_string=strchr(request_uri, '?'); int ulen=query_string? (query_string-request_uri) : strlen(request_uri); if (query_string) query_string++; int pfxlen=req->path_info? (req->path_info - req->uri) : 0; int plen=ulen-pfxlen; const char* path_info=request_uri+pfxlen; if (handler->uri && *handler->uri) { pfxlen=strlen(handler->uri); ulen=pfxlen+plen; char* u=nxb_alloc_obj(nxb, ulen+1); memcpy(u, handler->uri, pfxlen); memcpy(u+pfxlen, path_info, plen); u[ulen]='\0'; request_uri=u; path_info=request_uri+pfxlen; } const char* host_port=req->host? strchr(req->host, ':') : 0; int content_fd=0; if (req->content_length) { nxd_fwbuffer* fwb=nxweb_get_request_data(req, PYTHON_HANDLER_KEY).ptr; if (fwb) { if (fwb->error || fwb->size > fwb->max_size) { nxweb_send_http_error(resp, 413, "Request Entity Too Large"); // most likely cause return NXWEB_ERROR; } else if (req->content_received!=fwb->size) { nxweb_log_error("content_received does not match upload stored size for %s", req->uri); nxweb_send_http_error(resp, 500, "Internal Server Error"); return NXWEB_ERROR; } else { content_fd=fwb->fd; if (lseek(content_fd, 0, SEEK_SET)==-1) { nxweb_log_error("can't lseek() temp upload file for %s", req->uri); nxweb_send_http_error(resp, 500, "Internal Server Error"); return NXWEB_ERROR; } } } } nxweb_log_debug("invoke python"); PyGILState_STATE gstate=PyGILState_Ensure(); PyObject* py_func_args=PyTuple_New(1); PyObject* py_environ=PyDict_New(); assert(PyDict_Check(py_environ)); dict_set(py_environ, "SERVER_NAME", PyString_FromStringAndSize(req->host, host_port? (host_port-req->host) : strlen(req->host))); dict_set(py_environ, "SERVER_PORT", PyString_FromString(host_port? host_port+1 : "")); dict_set(py_environ, "SERVER_PROTOCOL", PyString_FromString(req->http11? "HTTP/1.1" : "HTTP/1.0")); dict_set(py_environ, "SERVER_SOFTWARE", PyString_FromString(PACKAGE_STRING)); dict_set(py_environ, "GATEWAY_INTERFACE", PyString_FromString("CGI/1.1")); dict_set(py_environ, "REQUEST_METHOD", PyString_FromString(req->method)); dict_set(py_environ, "REQUEST_URI", PyString_FromStringAndSize(request_uri, ulen)); dict_set(py_environ, "SCRIPT_NAME", PyString_FromStringAndSize(request_uri, pfxlen)); dict_set(py_environ, "PATH_INFO", PyString_FromStringAndSize(path_info, plen)); dict_set(py_environ, "QUERY_STRING", PyString_FromString(query_string? query_string : "")); dict_set(py_environ, "REMOTE_ADDR", PyString_FromString(conn->remote_addr)); dict_set(py_environ, "CONTENT_TYPE", PyString_FromString(req->content_type? req->content_type : "")); dict_set(py_environ, "CONTENT_LENGTH", PyInt_FromLong(req->content_received)); if (req->cookie) dict_set(py_environ, "HTTP_COOKIE", PyString_FromString(req->cookie)); if (req->host) dict_set(py_environ, "HTTP_HOST", PyString_FromString(req->host)); if (req->user_agent) dict_set(py_environ, "HTTP_USER_AGENT", PyString_FromString(req->user_agent)); if (req->if_modified_since) { struct tm tm; gmtime_r(&req->if_modified_since, &tm); char ims[32]; nxweb_format_http_time(ims, &tm); dict_set(py_environ, "HTTP_IF_MODIFIED_SINCE", PyString_FromString(ims)); } if (req->headers) { // write added headers // encode http headers into CGI variables; see 4.1.18 in https://tools.ietf.org/html/rfc3875 char hname[256]; memcpy(hname, "HTTP_", 5); char* h=hname+5; nx_simple_map_entry* itr; for (itr=nx_simple_map_itr_begin(req->headers); itr; itr=nx_simple_map_itr_next(itr)) { nx_strtoupper(h, itr->name); char* p; for (p=h; *p; p++) { if (*p=='-') *p='_'; } dict_set(py_environ, hname, PyString_FromString(itr->value)); } } dict_set(py_environ, "wsgi.url_scheme", PyString_FromString(conn->secure? "https" : "http")); if (req->content_length) { if (content_fd) { dict_set(py_environ, "nxweb.req.content_fd", PyInt_FromLong(content_fd)); } else { dict_set(py_environ, "nxweb.req.content", PyByteArray_FromStringAndSize(req->content? req->content : "", req->content_received)); } } if (req->if_modified_since) dict_set(py_environ, "nxweb.req.if_modified_since", PyLong_FromLong(req->if_modified_since)); dict_set(py_environ, "nxweb.req.uid", PyLong_FromLongLong(req->uid)); if (req->parent_req) { nxweb_http_request* preq=req->parent_req; while (preq->parent_req) preq=preq->parent_req; // find root request if (preq->uid) { dict_set(py_environ, "nxweb.req.root_uid", PyLong_FromLongLong(preq->uid)); } } // call python PyTuple_SetItem(py_func_args, 0, py_environ); PyObject* py_result=PyObject_CallObject(py_nxweb_on_request_func, py_func_args); Py_DECREF(py_func_args); if (py_result && PyTuple_Check(py_result) && PyTuple_Size(py_result)==3) { PyObject* py_status=PyTuple_GET_ITEM(py_result, 0); PyObject* py_headers=PyTuple_GET_ITEM(py_result, 1); PyObject* py_body=PyTuple_GET_ITEM(py_result, 2); if (py_status && PyString_Check(py_status)) { const char* status_string=PyString_AS_STRING(py_status); int status_code=0; const char* p=status_string; while (*p && *p>='0' && *p<='9') { status_code=status_code*10+(*p-'0'); p++; } while (*p && *p==' ') p++; if (status_code>=200 && status_code<600 && *p) { resp->status_code=status_code; resp->status=nxb_copy_str(nxb, p); } } if (py_headers && PyList_Check(py_headers)) { const int size=PyList_Size(py_headers); int i; for (i=0; i<size; i++) { PyObject* py_header_tuple=PyList_GET_ITEM(py_headers, i); if (py_header_tuple && PyTuple_Check(py_header_tuple) && PyTuple_Size(py_header_tuple)==2) { PyObject* py_name=PyTuple_GET_ITEM(py_header_tuple, 0); PyObject* py_value=PyTuple_GET_ITEM(py_header_tuple, 1); if (py_name && PyString_Check(py_name) && py_value && PyString_Check(py_value)) { nxweb_add_response_header_safe(resp, PyString_AS_STRING(py_name), PyString_AS_STRING(py_value)); } } } } if ((!resp->status_code || resp->status_code==200) && !resp->content_type) resp->content_type="text/html"; char* rcontent=0; nxe_ssize_t rsize=0; if (PyByteArray_Check(py_body)) { rcontent=PyByteArray_AS_STRING(py_body); rsize=PyByteArray_Size(py_body); } else if (PyString_Check(py_body)) { rcontent=PyString_AS_STRING(py_body); rsize=PyString_Size(py_body); } if (rcontent && rsize>0) nxweb_response_append_data(resp, rcontent, rsize); } else if (py_result && PyString_Check(py_result)) { resp->status_code=500; resp->status="Internal Server Error"; resp->content_type="text/html"; nxweb_log_error("python call failed: %s", PyString_AS_STRING(py_result)); nxweb_response_printf(resp, "python call failed: %H", PyString_AS_STRING(py_result)); } else { PyErr_Print(); nxweb_log_error("python call failed"); nxweb_response_printf(resp, "python call failed"); } Py_XDECREF(py_result); // Release the thread. No Python API allowed beyond this point. PyGILState_Release(gstate); nxweb_log_debug("invoke python complete"); return NXWEB_OK; }
static nxweb_result start_proxy_request(nxweb_http_server_connection* conn, nxweb_http_request* req, nxweb_http_proxy_request_data* rdata) { nxweb_log_debug("start_proxy_request"); nxe_loop* loop=conn->tdata->loop; nxweb_handler* handler=conn->handler; assert(handler->idx>=0 && handler->idx<NXWEB_MAX_PROXY_POOLS); nxd_http_proxy* hpx=nxd_http_proxy_pool_connect(&conn->tdata->proxy_pool[handler->idx]); rdata->proxy_request_complete=0; rdata->proxy_request_error=0; rdata->response_sending_started=0; if (hpx) { rdata->hpx=hpx; nxweb_http_request* preq=nxd_http_proxy_prepare(hpx); if (handler->proxy_copy_host) preq->host=req->host; preq->method=req->method; preq->head_method=req->head_method; preq->content_length=req->content_length; preq->content_type=req->content_type; /// Do not forward Accept-Encoding header if you want to process results (eg SSI) // preq->accept_encoding=req->accept_encoding; preq->expect_100_continue=!!req->content_length; if (handler->uri) { const char* path_info=req->path_info? req->path_info : req->uri; if (*handler->uri) { char* uri=nxb_alloc_obj(conn->hsp.nxb, strlen(handler->uri)+strlen(path_info)+1); strcat(strcpy(uri, handler->uri), path_info); preq->uri=uri; } else { preq->uri=path_info; } } else { preq->uri=req->uri; } preq->http11=1; preq->keep_alive=1; preq->user_agent=req->user_agent; preq->cookie=req->cookie; preq->if_modified_since=req->if_modified_since + nxd_http_proxy_pool_get_backend_time_delta(hpx->pool); preq->x_forwarded_for=conn->remote_addr; preq->x_forwarded_host=req->host; preq->x_forwarded_ssl=nxweb_server_config.listen_config[conn->lconf_idx].secure; preq->uid=req->uid; preq->parent_req=req->parent_req; preq->headers=req->headers; // need to filter these??? nxd_http_proxy_start_request(hpx, preq); nxe_init_subscriber(&rdata->proxy_events_sub, &nxweb_http_server_proxy_events_sub_class); nxe_subscribe(loop, &hpx->hcp.events_pub, &rdata->proxy_events_sub); nxd_rbuffer_init(&rdata->rb_resp, rdata->rbuf, NXWEB_RBUF_SIZE); nxe_connect_streams(loop, &hpx->hcp.resp_body_out, &rdata->rb_resp.data_in); if (req->content_length) { // receive body nxd_rbuffer_init(&rdata->rb_req, rdata->rbuf, NXWEB_RBUF_SIZE); // use same buffer area for request and response bodies, as they do not overlap in time conn->hsp.cls->connect_request_body_out(&conn->hsp, &rdata->rb_req.data_in); nxe_connect_streams(loop, &rdata->rb_req.data_out, &hpx->hcp.req_body_in); req->cdstate.monitor_only=1; conn->hsp.cls->start_receiving_request_body(&conn->hsp); } nxe_set_timer(loop, NXWEB_TIMER_BACKEND, &rdata->timer_backend); return NXWEB_OK; } else { nxweb_http_response* resp=&conn->hsp._resp; nxweb_send_http_error(resp, 502, "Bad Gateway"); return NXWEB_ERROR; } }