static int uwsgi_ssi_request(struct wsgi_request *wsgi_req) { struct uwsgi_buffer *ub = NULL; if (uwsgi_parse_vars(wsgi_req)) { return -1; } if (!wsgi_req->document_root_len || !wsgi_req->path_info_len) { uwsgi_log("[uwsgi-ssi] DOCUMENT_ROOT and PATH_INFO must be defined !!!\n"); uwsgi_500(wsgi_req); return UWSGI_OK; } char *filename = uwsgi_concat3n(wsgi_req->document_root, wsgi_req->document_root_len, "/", 1, wsgi_req->path_info, wsgi_req->path_info_len); size_t filename_len = wsgi_req->document_root_len + 1 + wsgi_req->path_info_len; // we expand the path for future security implementations char *real_filename = uwsgi_expand_path(filename, filename_len, NULL); free(filename); if (!real_filename) { uwsgi_404(wsgi_req); return UWSGI_OK; } struct uwsgi_buffer *ub_ssi = uwsgi_buffer_from_file(real_filename); free(real_filename); if (!ub_ssi) { uwsgi_500(wsgi_req); return UWSGI_OK; } ub = uwsgi_ssi_parse(wsgi_req, ub_ssi->buf, ub_ssi->pos); uwsgi_buffer_destroy(ub_ssi); if (!ub) { 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, ub->pos)) { uwsgi_500(wsgi_req); goto end; } // content_type if (uwsgi_response_add_content_type(wsgi_req, "text/html", 9)) { uwsgi_500(wsgi_req); goto end; } uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos); end: if (ub) { uwsgi_buffer_destroy(ub); } return UWSGI_OK; }
static int uwsgi_routing_func_ssi(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){ struct uwsgi_buffer *ub = NULL; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub_filename = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub_filename) goto end; struct uwsgi_buffer *ub_ssi = uwsgi_buffer_from_file(ub_filename->buf); uwsgi_buffer_destroy(ub_filename); if (!ub_ssi) goto end; ub = uwsgi_ssi_parse(wsgi_req, ub_ssi->buf, ub_ssi->pos); uwsgi_buffer_destroy(ub_ssi); if (!ub) goto end; if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto end; if (uwsgi_response_add_content_length(wsgi_req, ub->pos)) goto end; if (uwsgi_response_add_content_type(wsgi_req, "text/html", 9)) goto end; uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos); end: if (ub) uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_BREAK; }
static int uwsgi_routing_func_cache(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){ struct uwsgi_router_cache_conf *urcc = (struct uwsgi_router_cache_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, urcc->key, urcc->key_len); if (!ub) return UWSGI_ROUTE_BREAK; uint64_t valsize = 0; char *value = uwsgi_cache_magic_get(ub->buf, ub->pos, &valsize, urcc->name); uwsgi_buffer_destroy(ub); if (value) { if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto error; if (uwsgi_response_add_content_type(wsgi_req, urcc->content_type, urcc->content_type_len)) goto error; if (uwsgi_response_add_content_length(wsgi_req, valsize)) goto error; uwsgi_response_write_body_do(wsgi_req, value, valsize); free(value); if (ur->custom) return UWSGI_ROUTE_NEXT; return UWSGI_ROUTE_BREAK; } return UWSGI_ROUTE_NEXT; error: free(value); return UWSGI_ROUTE_BREAK; }
static int uwsgi_rpc_xmlrpc(struct wsgi_request *wsgi_req, xmlDoc *doc, char **argv, uint16_t *argvs, uint8_t *argc, char *response_buf) { char *method = NULL; xmlNode *element = xmlDocGetRootElement(doc); if (!element) return -1; if (strcmp((char *) element->name, "methodCall")) return -1; *argc = 0; xmlNode *node; for (node = element->children; node; node = node->next) { if (node->type == XML_ELEMENT_NODE) { if (!strcmp((char *) node->name, "methodName") && node->children) { method = (char *) node->children->content; } else if (!strcmp((char *) node->name, "params")) { if (uwsgi_rpc_xmlrpc_args(node, argv, argvs, argc)) return -1; } } } if (!method) return -1; wsgi_req->uh->pktsize = uwsgi_rpc(method, *argc, argv+1, argvs+1, response_buf); if (!wsgi_req->uh->pktsize) return -1; if (wsgi_req->uh->pktsize == UMAX16-1) return -1; // add final NULL byte response_buf[wsgi_req->uh->pktsize] = 0; xmlDoc *rdoc = xmlNewDoc(BAD_CAST "1.0"); xmlNode *m_response = xmlNewNode(NULL, BAD_CAST "methodResponse"); xmlDocSetRootElement(rdoc, m_response); xmlNode *x_params = xmlNewChild(m_response, NULL, BAD_CAST "params", NULL); xmlNode *x_param = xmlNewChild(x_params, NULL, BAD_CAST "param", NULL); xmlNode *x_value = xmlNewChild(x_param, NULL, BAD_CAST "value", NULL); xmlNewTextChild(x_value, NULL, BAD_CAST "string", BAD_CAST response_buf); xmlChar *xmlbuf; int xlen = 0; xmlDocDumpFormatMemory(rdoc, &xmlbuf, &xlen, 1); uwsgi_response_prepare_headers(wsgi_req,"200 OK", 6); uwsgi_response_add_content_length(wsgi_req, xlen); uwsgi_response_add_content_type(wsgi_req, "application/xml", 15); uwsgi_response_write_body_do(wsgi_req, (char *) xmlbuf, xlen); xmlFreeDoc(rdoc); xmlFree(xmlbuf); return 0; }
static int uwsgi_routing_func_xslt(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){ struct uwsgi_router_xslt_conf *urxc = (struct uwsgi_router_xslt_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_doc = NULL; struct uwsgi_buffer *ub_stylesheet = NULL; struct uwsgi_buffer *ub_params = NULL; struct uwsgi_buffer *ub_content_type = NULL; ub_doc = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urxc->doc, urxc->doc_len); if (!ub_doc) goto end; ub_stylesheet = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urxc->stylesheet, urxc->stylesheet_len); if (!ub_stylesheet) goto end; if (urxc->params) { ub_params = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urxc->params, urxc->params_len); if (!ub_params) goto end; } if (urxc->content_type) { ub_content_type = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urxc->content_type, urxc->content_type_len); if (!ub_content_type) goto end; } int rlen; char *output = uwsgi_xslt_apply( ub_doc->buf, ub_stylesheet->buf, ub_params ? ub_params->buf : NULL, &rlen); if (!output) goto end; if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto end; if (uwsgi_response_add_content_length(wsgi_req, rlen)) goto end; if (uwsgi_response_add_content_type(wsgi_req, urxc->content_type, urxc->content_type_len)) goto end; uwsgi_response_write_body_do(wsgi_req, output, rlen); xmlFree(output); end: if (ub_doc) uwsgi_buffer_destroy(ub_doc); if (ub_stylesheet) uwsgi_buffer_destroy(ub_stylesheet); if (ub_params) uwsgi_buffer_destroy(ub_params); if (ub_content_type) uwsgi_buffer_destroy(ub_content_type); return UWSGI_ROUTE_BREAK; }
static int uwsgi_wevdav_manage_proppatch(struct wsgi_request *wsgi_req, xmlDoc * doc) { char filename[PATH_MAX]; size_t filename_len = uwsgi_webdav_expand_path(wsgi_req, wsgi_req->path_info, wsgi_req->path_info_len, filename); if (filename_len == 0) { uwsgi_404(wsgi_req); return UWSGI_OK; } xmlNode *element = xmlDocGetRootElement(doc); if (!element) return -1; if (!element || (strcmp((char *) element->name, "propertyupdate"))) return -1; if (uwsgi_response_prepare_headers(wsgi_req, "207 Multi-Status", 16)) return -1; if (uwsgi_response_add_content_type(wsgi_req, "application/xml; charset=\"utf-8\"", 32)) return -1; xmlDoc *rdoc = xmlNewDoc(BAD_CAST "1.0"); xmlNode *multistatus = xmlNewNode(NULL, BAD_CAST "multistatus"); xmlDocSetRootElement(rdoc, multistatus); xmlNsPtr dav_ns = xmlNewNs(multistatus, BAD_CAST "DAV:", BAD_CAST "D"); xmlSetNs(multistatus, dav_ns); xmlNode *response = xmlNewChild(multistatus, dav_ns, BAD_CAST "response", NULL); char *uri = uwsgi_concat2n(wsgi_req->path_info, wsgi_req->path_info_len, "", 0); uint16_t uri_len = strlen(uri) ; char *encoded_uri = uwsgi_malloc( (uri_len * 3) + 1); http_url_encode(uri, &uri_len, encoded_uri); encoded_uri[uri_len] = 0; xmlNewChild(response, dav_ns, BAD_CAST "href", BAD_CAST encoded_uri); free(encoded_uri); // propfind can be "set" or "remove" xmlNode *node; for (node = element->children; node; node = node->next) { if (node->type == XML_ELEMENT_NODE) { if (node->ns && !strcmp((char *) node->ns->href, "DAV:")) { if (!strcmp((char *) node->name, "set")) { uwsgi_webdav_manage_prop_update(wsgi_req, node, response, filename, 0); } else if (!strcmp((char *) node->name, "remove")) { uwsgi_webdav_manage_prop_update(wsgi_req, node, response, filename, 1); } } } } if (!rdoc) return UWSGI_OK; xmlChar *xmlbuf; int xlen = 0; xmlDocDumpFormatMemory(rdoc, &xmlbuf, &xlen, 1); uwsgi_response_add_content_length(wsgi_req, xlen); uwsgi_response_write_body_do(wsgi_req, (char *) xmlbuf, xlen); #ifdef UWSGI_DEBUG uwsgi_log("\n%.*s\n", xlen, xmlbuf); #endif xmlFreeDoc(rdoc); xmlFree(xmlbuf); return UWSGI_OK; }
static int uwsgi_wevdav_manage_propfind(struct wsgi_request *wsgi_req, xmlDoc * doc) { char filename[PATH_MAX]; size_t filename_len = uwsgi_webdav_expand_path(wsgi_req, wsgi_req->path_info, wsgi_req->path_info_len, filename); if (filename_len == 0) { uwsgi_404(wsgi_req); return UWSGI_OK; } xmlDoc *rdoc = NULL; xmlNode *element = NULL; if (doc) { element = xmlDocGetRootElement(doc); if (!element) return -1; if (!element || strcmp((char *) element->name, "propfind")) return -1; } if (uwsgi_response_prepare_headers(wsgi_req, "207 Multi-Status", 16)) return -1; if (uwsgi_response_add_content_type(wsgi_req, "application/xml; charset=\"utf-8\"", 32)) return -1; if (doc) { // propfind must have a child (scan them until you find a valid one) xmlNode *node; for (node = element->children; node; node = node->next) { if (node->type == XML_ELEMENT_NODE) { if (node->ns && !strcmp((char *) node->ns->href, "DAV:")) { if (!strcmp((char *) node->name, "prop")) { rdoc = uwsgi_webdav_manage_prop(wsgi_req, node, filename, filename_len, 1); break; } if (!strcmp((char *) node->name, "allprop")) { rdoc = uwsgi_webdav_manage_prop(wsgi_req, NULL, filename, filename_len, 1); break; } if (!strcmp((char *) node->name, "propname")) { rdoc = uwsgi_webdav_manage_prop(wsgi_req, node, filename, filename_len, 0); break; } } } } } else { rdoc = uwsgi_webdav_manage_prop(wsgi_req, NULL, filename, filename_len, 1); } if (!rdoc) return UWSGI_OK; xmlChar *xmlbuf; int xlen = 0; xmlDocDumpFormatMemory(rdoc, &xmlbuf, &xlen, 1); uwsgi_response_add_content_length(wsgi_req, xlen); uwsgi_response_write_body_do(wsgi_req, (char *) xmlbuf, xlen); #ifdef UWSGI_DEBUG uwsgi_log("\n%.*s\n", xlen, xmlbuf); #endif xmlFreeDoc(rdoc); xmlFree(xmlbuf); return UWSGI_OK; }
static int uwsgi_wevdav_manage_get(struct wsgi_request *wsgi_req, int send_body) { char filename[PATH_MAX]; size_t filename_len = uwsgi_webdav_expand_path(wsgi_req, wsgi_req->path_info, wsgi_req->path_info_len, filename); if (!filename_len) { uwsgi_404(wsgi_req); return UWSGI_OK; } if (uwsgi_is_dir(filename)) { uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6); if (send_body) { uwsgi_webdav_dirlist(wsgi_req, filename); } return UWSGI_OK; } int fd = open(filename, O_RDONLY); if (fd < 0) { uwsgi_403(wsgi_req); return UWSGI_OK; } struct stat st; if (fstat(fd, &st)) { close(fd); uwsgi_403(wsgi_req); return UWSGI_OK; } if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto end; // add content_length if (uwsgi_response_add_content_length(wsgi_req, st.st_size)) goto end; // add last-modified if (uwsgi_response_add_last_modified(wsgi_req, st.st_mtime)) goto end; // add mime_type size_t mime_type_len = 0; char *mime_type = uwsgi_get_mime_type(filename, filename_len, &mime_type_len); if (mime_type) { if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) goto end; } // add ETag (based on file mtime, not rock-solid, but good enough) char *etag = uwsgi_num2str(st.st_mtime); if (uwsgi_response_add_header(wsgi_req, "ETag", 4, etag, strlen(etag))) { free(etag); goto end; } free(etag); // start sending the file (note: we do not use sendfile() api, for being able to use caching and transformations) if (!send_body) goto end; // use a pretty big buffer (for performance reasons) char buf[32768]; size_t remains = st.st_size; while (remains > 0) { ssize_t rlen = read(fd, buf, UMIN(32768, remains)); if (rlen <= 0) { uwsgi_error("uwsgi_wevdav_manage_get/read()"); break; } remains -= rlen; if (uwsgi_response_write_body_do(wsgi_req, buf, rlen)) { break; } } end: close(fd); return UWSGI_OK; }
// "next" || "continue" || "break(.*)" || "goon" || "goto .+" static int uwsgi_routing_func_rpc_ret(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { int ret = -1; // this is the list of args char *argv[UMAX8]; // this is the size of each argument uint16_t argvs[UMAX8]; // this is a placeholder for tmp uwsgi_buffers struct uwsgi_buffer *ubs[UMAX8]; char **r_argv = (char **) ur->data2; uint16_t *r_argvs = (uint16_t *) ur->data3; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); uint64_t i; for(i=0;i<ur->custom;i++) { ubs[i] = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, r_argv[i], r_argvs[i]); if (!ubs[i]) goto end; argv[i] = ubs[i]->buf; argvs[i] = ubs[i]->pos; } // ok we now need to check it it is a local call or a remote one char *func = uwsgi_str(ur->data); char *remote = NULL; char *at = strchr(func, '@'); if (at) { *at = 0; remote = at+1; } uint16_t size; char *response = uwsgi_do_rpc(remote, func, ur->custom, argv, argvs, &size); free(func); if (!response) goto end; ret = UWSGI_ROUTE_CONTINUE; if (!uwsgi_strncmp(response, size, "next", 4 )) { ret = UWSGI_ROUTE_NEXT; } else if (!uwsgi_strncmp(response, size, "continue", 8 )) { ret = UWSGI_ROUTE_CONTINUE; } else if (!uwsgi_starts_with(response, size, "break", 5 )) { ret = UWSGI_ROUTE_BREAK; if (size > 6) { if (uwsgi_response_prepare_headers(wsgi_req, response+6, size-6)) goto end0; if (uwsgi_response_add_connection_close(wsgi_req)) goto end0; if (uwsgi_response_add_content_type(wsgi_req, "text/plain", 10)) goto end0; // no need to check for return value uwsgi_response_write_headers_do(wsgi_req); } } else if (!uwsgi_starts_with(response, size, "goto ", 5)) { ret = UWSGI_ROUTE_BREAK; if (size > 5) { // find the label struct uwsgi_route *routes = uwsgi.routes; while(routes) { if (!routes->label) goto next; if (!uwsgi_strncmp(routes->label, routes->label_len, response+5, size-5)) { ret = UWSGI_ROUTE_NEXT; wsgi_req->route_goto = routes->pos; goto found; } next: routes = routes->next; } goto end0; found: if (wsgi_req->route_goto <= wsgi_req->route_pc) { wsgi_req->route_goto = 0; uwsgi_log("[uwsgi-route] ERROR \"goto\" instruction can only jump forward (check your label !!!)\n"); ret = UWSGI_ROUTE_BREAK; } } } end0: free(response); end: for(i=0;i<ur->custom;i++) { if (ubs[i] != NULL) { uwsgi_buffer_destroy(ubs[i]); } } return ret; }
static int uwsgi_rpc_request(struct wsgi_request *wsgi_req) { // this is the list of args char *argv[UMAX8]; // this is the size of each argument uint16_t argvs[UMAX8]; // maximum number of supported arguments uint8_t argc = 0xff; // response output char response_buf[UMAX16]; /* Standard RPC request */ if (!wsgi_req->uh->pktsize) { uwsgi_log("Empty RPC request. skip.\n"); return -1; } if (wsgi_req->uh->modifier2 == 2) { if (uwsgi_parse_vars(wsgi_req)) { uwsgi_log("Invalid RPC request. skip.\n"); return -1; } if (wsgi_req->path_info_len == 0) { uwsgi_500(wsgi_req); return UWSGI_OK; } char *args = NULL; if (wsgi_req->path_info[0] == '/') { args = uwsgi_concat2n(wsgi_req->path_info+1, wsgi_req->path_info_len-1, "", 0); } else { args = uwsgi_concat2n(wsgi_req->path_info, wsgi_req->path_info_len, "", 0); } argc = 0; argv[0] = strtok(args, "/"); if (!argv[0]) { free(args); uwsgi_500(wsgi_req); return UWSGI_OK; } char *p = strtok(NULL, "/"); while(p) { argc++; argv[argc] = p; argvs[argc] = strlen(p); p = strtok(NULL, "/"); } wsgi_req->uh->pktsize = uwsgi_rpc(argv[0], argc, argv+1, argvs+1, response_buf); free(args); if (!wsgi_req->uh->pktsize) { uwsgi_404(wsgi_req); return UWSGI_OK; } if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) return 1; if (uwsgi_response_add_content_length(wsgi_req, wsgi_req->uh->pktsize)) return -1; uint16_t ctype_len = 0; char *ctype = uwsgi_get_var(wsgi_req, "HTTP_ACCEPT", 11, &ctype_len); if (ctype && strcmp(ctype, "*/*") && strcmp(ctype, "*")) { if (uwsgi_response_add_content_type(wsgi_req, ctype, ctype_len)) return -1; } else { if (uwsgi_response_add_content_type(wsgi_req, "application/binary", 18)) return -1; } goto sendbody; } #ifdef UWSGI_XML_LIBXML2 if (wsgi_req->uh->modifier2 == 3) { if (wsgi_req->post_cl == 0) { uwsgi_500(wsgi_req); return UWSGI_OK; } ssize_t body_len = 0; char *body = uwsgi_request_body_read(wsgi_req, wsgi_req->post_cl, &body_len); xmlDoc *doc = xmlReadMemory(body, body_len, NULL, NULL, 0); if (!doc) { uwsgi_500(wsgi_req); return UWSGI_OK; } int ret = uwsgi_rpc_xmlrpc(wsgi_req, doc, argv, argvs, &argc, response_buf); xmlFreeDoc(doc); if (ret) { uwsgi_500(wsgi_req); } return UWSGI_OK; } #endif if (uwsgi_parse_array(wsgi_req->buffer, wsgi_req->uh->pktsize, argv, argvs, &argc)) { uwsgi_log("Invalid RPC request. skip.\n"); return -1; } // call the function (output will be in wsgi_req->buffer) wsgi_req->uh->pktsize = uwsgi_rpc(argv[0], argc-1, argv+1, argvs+1, response_buf); // using modifier2 we may want a raw output if (wsgi_req->uh->modifier2 == 0) { if (uwsgi_response_write_body_do(wsgi_req, (char *) wsgi_req->uh, 4)) { return -1; } } sendbody: // write the response uwsgi_response_write_body_do(wsgi_req, response_buf, wsgi_req->uh->pktsize); 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; }
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; // static file - don't update avg_rt after request wsgi_req->do_not_account_avg_rt = 1; if (urfc->no_headers) { uwsgi_buffer_destroy(ub_s); 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; }
static void uwsgi_webdav_dirlist(struct wsgi_request *wsgi_req, char *dir) { struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); if (uwsgi_buffer_append(ub, "<html><head><title>", 19)) goto end; if (uwsgi_buffer_append(ub, dir, strlen(dir))) goto end; if (uwsgi_buffer_append(ub, "</title>", 8)) goto end; struct uwsgi_string_list *usl = udav.css; while(usl) { if (uwsgi_buffer_append(ub, "<link rel=\"stylesheet\" href=\"", 29)) goto end; if (uwsgi_buffer_append(ub, usl->value, usl->len)) goto end; if (uwsgi_buffer_append(ub, "\" type=\"text/css\">", 18)) goto end; usl = usl->next; } usl = udav.javascript; while(usl) { if (uwsgi_buffer_append(ub, "<script src=\"", 13)) goto end; if (uwsgi_buffer_append(ub, usl->value, usl->len)) goto end; if (uwsgi_buffer_append(ub, "\"></script>", 11)) goto end; usl = usl->next; } if (uwsgi_buffer_append(ub, "</head><body>", 13)) goto end; if (udav.div) { if (uwsgi_buffer_append(ub, "<div id=\"", 9)) goto end; if (uwsgi_buffer_append(ub, udav.div, strlen(udav.div))) goto end; if (uwsgi_buffer_append(ub, "\">", 2)) goto end; } else { if (uwsgi_buffer_append(ub, "<div>", 5)) goto end; } if (uwsgi_webdav_dirlist_add_item(ub, "..", 2, 1)) goto end; #ifdef __linux__ struct dirent **tasklist; int n = scandir(dir, &tasklist, 0, versionsort); if (n < 0) goto end; int i; for(i=0;i<n;i++) { if (tasklist[i]->d_name[0] == '.') goto next; if (uwsgi_webdav_dirlist_add_item(ub, tasklist[i]->d_name, strlen(tasklist[i]->d_name), tasklist[i]->d_type == DT_DIR ? 1 : 0)) { free(tasklist[i]); free(tasklist); goto end; } next: free(tasklist[i]); } free(tasklist); #else DIR *d = opendir(dir); for (;;) { struct dirent *de_r = NULL; struct dirent de; if (readdir_r(d, &de, &de_r)) goto end; if (de_r == NULL) break; // skip items startign with a dot if (de.d_name[0] == '.') continue; if (uwsgi_webdav_dirlist_add_item(ub, de.d_name, strlen(de.d_name), de.d_type == DT_DIR ? 1 : 0)) goto end; } closedir(d); #endif if (uwsgi_buffer_append(ub, "</ul></div></body></html>", 25)) goto end; if (uwsgi_response_add_content_type(wsgi_req, "text/html", 9)) goto end; if (uwsgi_response_add_content_length(wsgi_req, ub->pos)) goto end; uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos); end: uwsgi_buffer_destroy(ub); }
static int uwsgi_rados_request(struct wsgi_request *wsgi_req) { char filename[PATH_MAX+1]; if (!wsgi_req->len) { uwsgi_log( "Empty request. skip.\n"); return -1; } if (uwsgi_parse_vars(wsgi_req)) { return -1; } // blocks empty paths if (wsgi_req->path_info_len == 0 || wsgi_req->path_info_len > PATH_MAX) { uwsgi_403(wsgi_req); return UWSGI_OK; } wsgi_req->app_id = uwsgi_get_app_id(wsgi_req, wsgi_req->appid, wsgi_req->appid_len, rados_plugin.modifier1); if (wsgi_req->app_id == -1 && !uwsgi.no_default_app && uwsgi.default_app > -1) { if (uwsgi_apps[uwsgi.default_app].modifier1 == rados_plugin.modifier1) { wsgi_req->app_id = uwsgi.default_app; } } if (wsgi_req->app_id == -1) { uwsgi_404(wsgi_req); return UWSGI_OK; } struct uwsgi_app *ua = &uwsgi_apps[wsgi_req->app_id]; if (wsgi_req->path_info_len > ua->mountpoint_len && memcmp(wsgi_req->path_info, ua->mountpoint, ua->mountpoint_len) == 0) { memcpy(filename, wsgi_req->path_info+ua->mountpoint_len, wsgi_req->path_info_len-ua->mountpoint_len); filename[wsgi_req->path_info_len-ua->mountpoint_len] = 0; } else { memcpy(filename, wsgi_req->path_info, wsgi_req->path_info_len); filename[wsgi_req->path_info_len] = 0; } // in multithread mode the memory is different (as we need a ctx for each thread) !!! rados_ioctx_t ctx; if (uwsgi.threads > 1) { rados_ioctx_t *ctxes = (rados_ioctx_t *) ua->responder0; ctx = ctxes[wsgi_req->async_id]; } else { ctx = (rados_ioctx_t) ua->responder0; } struct uwsgi_rados_mountpoint *urmp = (struct uwsgi_rados_mountpoint *) ua->responder1; uint64_t stat_size = 0; time_t stat_mtime = 0; struct uwsgi_rados_io *urio = &urados.urio[wsgi_req->async_id]; if (uwsgi.async > 0) { // no need to lock here (the rid protect us) if (pipe(urio->fds)) { uwsgi_error("uwsgi_rados_read_async()/pipe()"); uwsgi_500(wsgi_req); return UWSGI_OK; } } int ret = -1; int timeout = urmp->timeout ? urmp->timeout : urados.timeout; if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "OPTIONS", 7)) { if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto end; if (uwsgi_response_add_header(wsgi_req, "Dav", 3, "1", 1)) goto end; struct uwsgi_buffer *ub_allow = uwsgi_buffer_new(64); if (uwsgi_buffer_append(ub_allow, "OPTIONS, GET, HEAD", 18)) { uwsgi_buffer_destroy(ub_allow); goto end; } if (urmp->allow_put) { if (uwsgi_buffer_append(ub_allow, ", PUT", 5)) { uwsgi_buffer_destroy(ub_allow); goto end; } } if (urmp->allow_delete) { if (uwsgi_buffer_append(ub_allow, ", DELETE", 8)) { uwsgi_buffer_destroy(ub_allow); goto end; } } if (urmp->allow_mkcol) { if (uwsgi_buffer_append(ub_allow, ", MKCOL", 7)) { uwsgi_buffer_destroy(ub_allow); goto end; } } if (urmp->allow_propfind) { if (uwsgi_buffer_append(ub_allow, ", PROPFIND", 10)) { uwsgi_buffer_destroy(ub_allow); goto end; } } uwsgi_response_add_header(wsgi_req, "Allow", 5, ub_allow->buf, ub_allow->pos); uwsgi_buffer_destroy(ub_allow); goto end; } // empty paths are mapped to propfind if (wsgi_req->path_info_len == 1 && wsgi_req->path_info[0] == '/') { if (urmp->allow_propfind && !uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "PROPFIND", 8)) { uwsgi_rados_propfind(wsgi_req, ctx, NULL, 0, 0, timeout); goto end; } uwsgi_405(wsgi_req); goto end; } // MKCOL does not require stat if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "MKCOL", 5)) { if (!urmp->allow_mkcol) { uwsgi_405(wsgi_req); goto end; } ret = rados_pool_create(urmp->cluster, filename); if (ret < 0) { if (ret == -EEXIST) { uwsgi_405(wsgi_req); } else { uwsgi_500(wsgi_req); } goto end; } uwsgi_response_prepare_headers(wsgi_req, "201 Created", 11); goto end; } if (uwsgi.async > 0) { ret = uwsgi_rados_async_stat(urio, ctx, filename, &stat_size, &stat_mtime, timeout); } else { ret = rados_stat(ctx, filename, &stat_size, &stat_mtime); } // PUT AND MKCOL can be used for non-existent objects if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "PUT", 3)) { if (!urmp->allow_put) { uwsgi_405(wsgi_req); goto end; } if (ret == 0) { if (uwsgi_rados_delete(wsgi_req, ctx, filename, timeout)) { uwsgi_500(wsgi_req); goto end; } } if (uwsgi_rados_put(wsgi_req, ctx, filename, urmp->put_buffer_size, timeout)) { uwsgi_500(wsgi_req); goto end; } uwsgi_response_prepare_headers(wsgi_req, "201 Created", 11); goto end; } else if (ret < 0) { if (ret == -ENOENT) uwsgi_404(wsgi_req); else uwsgi_403(wsgi_req); goto end; } if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "DELETE", 6)) { if (!urmp->allow_delete) { uwsgi_405(wsgi_req); goto end; } if (uwsgi_rados_delete(wsgi_req, ctx, filename, timeout)) { uwsgi_403(wsgi_req); goto end; } uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6); goto end; } if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "PROPFIND", 8)) { if (!urmp->allow_propfind) { uwsgi_405(wsgi_req); goto end; } uwsgi_rados_propfind(wsgi_req, ctx, filename, stat_size, stat_mtime, timeout); goto end; } if (uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4) && uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "GET", 3)) { uwsgi_405(wsgi_req); goto end; } uint64_t offset = 0; uint64_t remains = stat_size; uwsgi_request_fix_range_for_size(wsgi_req, remains); switch (wsgi_req->range_parsed) { case UWSGI_RANGE_INVALID: if (uwsgi_response_prepare_headers(wsgi_req, "416 Requested Range Not Satisfiable", 35)) goto end; if (uwsgi_response_add_content_range(wsgi_req, -1, -1, stat_size)) goto end; return 0; case UWSGI_RANGE_VALID: offset = wsgi_req->range_from; remains = wsgi_req->range_to - wsgi_req->range_from + 1; if (uwsgi_response_prepare_headers(wsgi_req, "206 Partial Content", 19)) goto end; break; default: /* UWSGI_RANGE_NOT_PARSED */ if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) return -1; } size_t mime_type_len = 0; char *mime_type = uwsgi_get_mime_type(wsgi_req->path_info, wsgi_req->path_info_len, &mime_type_len); if (mime_type) { if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) goto end; } if (uwsgi_response_add_last_modified(wsgi_req, (uint64_t) stat_mtime)) goto end; // set Content-Length to actual result size if (uwsgi_response_add_content_length(wsgi_req, remains)) goto end; if (wsgi_req->range_parsed == UWSGI_RANGE_VALID) { // here use the original size !!! if (uwsgi_response_add_content_range(wsgi_req, wsgi_req->range_from, wsgi_req->range_to, stat_size)) goto end; } // skip body on HEAD if (uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) { if (uwsgi.async > 0) { if (uwsgi_rados_read_async(wsgi_req, ctx, filename, offset, remains, urmp->buffer_size, timeout)) goto end; } else { if (uwsgi_rados_read_sync(wsgi_req, ctx, filename, offset, remains, urmp->buffer_size)) goto end; } } end: if (uwsgi.async > 0) { close(urio->fds[0]); close(urio->fds[1]); } return UWSGI_OK; }
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); }
int uwsgi_real_file_serve(struct wsgi_request *wsgi_req, char *real_filename, size_t real_filename_len, struct stat *st) { size_t mime_type_size = 0; char http_last_modified[49]; if (uwsgi.threads > 1) pthread_mutex_lock(&uwsgi.lock_static); char *mime_type = uwsgi_get_mime_type(real_filename, real_filename_len, &mime_type_size); if (uwsgi.threads > 1) pthread_mutex_unlock(&uwsgi.lock_static); if (wsgi_req->if_modified_since_len) { time_t ims = parse_http_date(wsgi_req->if_modified_since, wsgi_req->if_modified_since_len); if (st->st_mtime <= ims) { uwsgi_response_prepare_headers(wsgi_req, "304 Not Modified", 16); return uwsgi_response_write_headers_do(wsgi_req); } } #ifdef UWSGI_DEBUG uwsgi_log("[uwsgi-fileserve] file %s found\n", real_filename); #endif size_t fsize = st->st_size; if (wsgi_req->range_to) { fsize = wsgi_req->range_to - wsgi_req->range_from; if (fsize > (size_t)st->st_size) { fsize = st->st_size; } } else { // reset in case of inconsistent size if (wsgi_req->range_from > fsize) { wsgi_req->range_from = 0; fsize = 0 ; } else { fsize -= wsgi_req->range_from; } } // HTTP status if (fsize > 0 && (wsgi_req->range_from || wsgi_req->range_to)) { if (uwsgi_response_prepare_headers(wsgi_req, "206 Partial Content", 19)) return -1; } else { if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) return -1; } #ifdef UWSGI_PCRE uwsgi_add_expires(wsgi_req, real_filename, real_filename_len, st); uwsgi_add_expires_path_info(wsgi_req, st); uwsgi_add_expires_uri(wsgi_req, st); #endif // Content-Type (if available) if (mime_type_size > 0 && mime_type) { if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_size)) return -1; // check for content-type related headers uwsgi_add_expires_type(wsgi_req, mime_type, mime_type_size, st); } // increase static requests counter uwsgi.workers[uwsgi.mywid].cores[wsgi_req->async_id].static_requests++; // nginx if (uwsgi.file_serve_mode == 1) { if (uwsgi_response_add_header(wsgi_req, "X-Accel-Redirect", 16, real_filename, real_filename_len)) return -1; // this is the final header (\r\n added) int size = set_http_date(st->st_mtime, http_last_modified); if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1; } // apache else if (uwsgi.file_serve_mode == 2) { if (uwsgi_response_add_header(wsgi_req, "X-Sendfile", 10, real_filename, real_filename_len)) return -1; // this is the final header (\r\n added) int size = set_http_date(st->st_mtime, http_last_modified); if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1; } // raw else { // here we need to choose if we want the gzip variant; if (uwsgi_static_want_gzip(wsgi_req, real_filename, real_filename_len, st)) { if (uwsgi_response_add_header(wsgi_req, "Content-Encoding", 16, "gzip", 4)) return -1; } // set Content-Length (to fsize NOT st->st_size) if (uwsgi_response_add_content_length(wsgi_req, fsize)) return -1; if (fsize > 0 && (wsgi_req->range_from || wsgi_req->range_to)) { // here use teh original size !!! if (uwsgi_response_add_content_range(wsgi_req, wsgi_req->range_from, wsgi_req->range_to, st->st_size)) return -1; } int size = set_http_date(st->st_mtime, http_last_modified); if (uwsgi_response_add_header(wsgi_req, "Last-Modified", 13, http_last_modified, size)) return -1; // if it is a HEAD request just skip transfer if (!uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) { wsgi_req->status = 200; return 0; } // Ok, the file must be transferred from uWSGI // offloading will be automatically managed int fd = open(real_filename, O_RDONLY); if (fd < 0) return -1; // fd will be closed in the following function uwsgi_response_sendfile_do(wsgi_req, fd, wsgi_req->range_from, fsize); } wsgi_req->status = 200; 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; }
static int uwsgi_rados_request(struct wsgi_request *wsgi_req) { char filename[PATH_MAX+1]; if (!wsgi_req->uh->pktsize) { uwsgi_log( "Empty request. skip.\n"); return -1; } if (uwsgi_parse_vars(wsgi_req)) { return -1; } // blocks empty paths if (wsgi_req->path_info_len == 0 || wsgi_req->path_info_len > PATH_MAX) { uwsgi_403(wsgi_req); return UWSGI_OK; } wsgi_req->app_id = uwsgi_get_app_id(wsgi_req, wsgi_req->appid, wsgi_req->appid_len, rados_plugin.modifier1); if (wsgi_req->app_id == -1 && !uwsgi.no_default_app && uwsgi.default_app > -1) { if (uwsgi_apps[uwsgi.default_app].modifier1 == rados_plugin.modifier1) { wsgi_req->app_id = uwsgi.default_app; } } if (wsgi_req->app_id == -1) { uwsgi_404(wsgi_req); return UWSGI_OK; } struct uwsgi_app *ua = &uwsgi_apps[wsgi_req->app_id]; if (wsgi_req->path_info_len > ua->mountpoint_len && memcmp(wsgi_req->path_info, ua->mountpoint, ua->mountpoint_len) == 0) { memcpy(filename, wsgi_req->path_info+ua->mountpoint_len, wsgi_req->path_info_len-ua->mountpoint_len); } else { memcpy(filename, wsgi_req->path_info, wsgi_req->path_info_len); } filename[wsgi_req->path_info_len] = 0; struct { uint64_t size; time_t mtime; } st; rados_ioctx_t ctx = ua->responder1; int r = rados_stat(ctx, filename, &st.size, &st.mtime); if (r < 0) { if (r == -ENOENT) uwsgi_404(wsgi_req); else uwsgi_403(wsgi_req); return UWSGI_OK; } if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto end; size_t mime_type_len = 0; char *mime_type = uwsgi_get_mime_type(wsgi_req->path_info, wsgi_req->path_info_len, &mime_type_len); if (mime_type) { if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) goto end; } if (uwsgi_response_add_last_modified(wsgi_req, (uint64_t) st.mtime)) goto end; if (uwsgi_response_add_content_length(wsgi_req, st.size)) goto end; // skip body on HEAD if (uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) { size_t remains = st.size; if (uwsgi.async > 1) { if (uwsgi_rados_read_async(wsgi_req, ctx, filename, remains)) goto end; } else { if (uwsgi_rados_read_sync(wsgi_req, ctx, filename, remains)) goto end; } } end: return UWSGI_OK; }
int uwsgi_routing_func_fastfile(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { struct stat st; int ret = UWSGI_ROUTE_BREAK; 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; // static file - don't update avg_rt after request wsgi_req->do_not_account_avg_rt = 1; if (urfc->no_headers) { uwsgi_buffer_destroy(ub_s); 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 (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: if (!wsgi_req->headers_sent) { if (uwsgi_response_write_headers_do(wsgi_req)) goto end2; } if (wsgi_req->socket->can_offload) { if (!uwsgi_offload_request_sendfile_do(wsgi_req, fd, st.st_size)) { wsgi_req->via = UWSGI_VIA_OFFLOAD; wsgi_req->response_size += st.st_size; // the fd will be closed by the offload engine goto end; } } if (!uwsgi_simple_sendfile(wsgi_req, fd, 0, st.st_size)) { wsgi_req->via = UWSGI_VIA_SENDFILE; wsgi_req->response_size += st.st_size; } end2: close(fd); end: uwsgi_buffer_destroy(ub); return ret; }
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; }
static int uwsgi_glusterfs_request(struct wsgi_request *wsgi_req) { char filename[PATH_MAX+1]; /* Standard GlusterFS request */ if (!wsgi_req->uh->pktsize) { uwsgi_log( "Empty GlusterFS request. skip.\n"); return -1; } if (uwsgi_parse_vars(wsgi_req)) { return -1; } // blocks empty paths if (wsgi_req->path_info_len == 0 || wsgi_req->path_info_len > PATH_MAX) { uwsgi_403(wsgi_req); return UWSGI_OK; } wsgi_req->app_id = uwsgi_get_app_id(wsgi_req, wsgi_req->appid, wsgi_req->appid_len, glusterfs_plugin.modifier1); if (wsgi_req->app_id == -1 && !uwsgi.no_default_app && uwsgi.default_app > -1) { if (uwsgi_apps[uwsgi.default_app].modifier1 == glusterfs_plugin.modifier1) { wsgi_req->app_id = uwsgi.default_app; } } if (wsgi_req->app_id == -1) { uwsgi_404(wsgi_req); return UWSGI_OK; } struct uwsgi_app *ua = &uwsgi_apps[wsgi_req->app_id]; memcpy(filename, wsgi_req->path_info, wsgi_req->path_info_len); filename[wsgi_req->path_info_len] = 0; glfs_fd_t *fd = glfs_open((glfs_t *) ua->interpreter, filename, O_RDONLY); if (!fd) { uwsgi_404(wsgi_req); return UWSGI_OK; } struct stat st; if (glfs_fstat(fd, &st)) { uwsgi_403(wsgi_req); return UWSGI_OK; } if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) goto end; size_t mime_type_len = 0; char *mime_type = uwsgi_get_mime_type(wsgi_req->path_info, wsgi_req->path_info_len, &mime_type_len); if (mime_type) { if (uwsgi_response_add_content_type(wsgi_req, mime_type, mime_type_len)) goto end; } if (uwsgi_response_add_last_modified(wsgi_req, (uint64_t) st.st_mtime)) goto end; if (uwsgi_response_add_content_length(wsgi_req, st.st_size)) goto end; // skip body on HEAD if (uwsgi_strncmp(wsgi_req->method, wsgi_req->method_len, "HEAD", 4)) { size_t remains = st.st_size; while(remains > 0) { char buf[8192]; ssize_t rlen = glfs_read (fd, buf, UMIN(remains, 8192), 0); if (rlen <= 0) goto end; if (uwsgi_response_write_body_do(wsgi_req, buf, rlen)) goto end; remains -= rlen; } } end: glfs_close(fd); return UWSGI_OK; }
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; }