// be tolerant on errors static int uwsgi_routing_func_cache_store(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){ struct uwsgi_router_cache_conf *urcc = (struct uwsgi_router_cache_conf *) ur->data2; // overwrite previous run if (wsgi_req->cache_it) { uwsgi_buffer_destroy(wsgi_req->cache_it); wsgi_req->cache_it = NULL; } if (wsgi_req->cache_it_to) { uwsgi_buffer_destroy(wsgi_req->cache_it_to); wsgi_req->cache_it_to = NULL; } // build key and name char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); wsgi_req->cache_it = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->key, urcc->key_len); if (!wsgi_req->cache_it) return UWSGI_ROUTE_NEXT; if (urcc->name) { wsgi_req->cache_it_to = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urcc->name, urcc->name_len); if (!wsgi_req->cache_it_to) { uwsgi_buffer_destroy(wsgi_req->cache_it); wsgi_req->cache_it = NULL; } } wsgi_req->cache_it_expires = urcc->expires; return UWSGI_ROUTE_NEXT; }
// metricinc/metricdec/metricmul/metricdiv/metricset static int uwsgi_routing_func_metricmath(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){ struct uwsgi_router_metric_conf *urmc = (struct uwsgi_router_metric_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, urmc->name, urmc->name_len); if (!ub) return UWSGI_ROUTE_BREAK; struct uwsgi_buffer *ub_val = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urmc->value, urmc->value_len); if (!ub_val) { uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_BREAK; } int64_t num = strtol(ub_val->buf, NULL, 10); uwsgi_buffer_destroy(ub_val); if (urmc->func(ub->buf, NULL, num)) { uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_BREAK; } uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_NEXT; }
static int uwsgi_routing_func_expires(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){ struct uwsgi_router_expires_conf *urec = (struct uwsgi_router_expires_conf *) ur->data2; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); uint64_t expires = 0; if (urec->filename) { struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urec->filename, urec->filename_len); if (!ub) return UWSGI_ROUTE_BREAK; struct stat st; if (stat(ub->buf, &st)) { uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_BREAK; } expires = st.st_mtime; uwsgi_buffer_destroy(ub); } else if (urec->unixt) { struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urec->unixt, urec->unixt_len); if (!ub) return UWSGI_ROUTE_BREAK; expires = strtoul(ub->buf, NULL, 10); uwsgi_buffer_destroy(ub); } if (urec->value) { struct uwsgi_buffer *ub = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, urec->value, urec->value_len); if (!ub) return UWSGI_ROUTE_BREAK; expires += atoi(ub->buf); uwsgi_buffer_destroy(ub); } char expires_str[7 + 2 + 31]; int len = uwsgi_http_date((time_t) expires, expires_str + 9); if (!len) return UWSGI_ROUTE_BREAK; memcpy(expires_str, "Expires: ", 9); uwsgi_additional_header_add(wsgi_req, expires_str, 9 + len); return UWSGI_ROUTE_NEXT; }
static int uwsgi_routing_func_rewrite(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { char *tmp_qs = 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 = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub) return UWSGI_ROUTE_BREAK; uint16_t path_info_len = ub->pos; uint16_t query_string_len = 0; char *query_string = memchr(ub->buf, '?', ub->pos); if (query_string) { path_info_len = query_string - ub->buf; query_string++; query_string_len = ub->pos - (path_info_len + 1); if (wsgi_req->query_string_len > 0) { tmp_qs = uwsgi_concat4n(query_string, query_string_len, "&", 1, wsgi_req->query_string, wsgi_req->query_string_len, "", 0); query_string = tmp_qs; query_string_len = strlen(query_string); } } // over engineering, could be required in the future... else { if (wsgi_req->query_string_len > 0) { query_string = wsgi_req->query_string; query_string_len = wsgi_req->query_string_len; } else { query_string = ""; } } char *ptr = uwsgi_req_append(wsgi_req, "PATH_INFO", 9, ub->buf, path_info_len); if (!ptr) goto clear; // set new path_info wsgi_req->path_info = ptr; wsgi_req->path_info_len = path_info_len; ptr = uwsgi_req_append(wsgi_req, "QUERY_STRING", 12, query_string, query_string_len); if (!ptr) goto clear; // set new query_string wsgi_req->query_string = ptr; wsgi_req->query_string_len = query_string_len; uwsgi_buffer_destroy(ub); if (tmp_qs) free(tmp_qs); if (ur->custom) return UWSGI_ROUTE_CONTINUE; return UWSGI_ROUTE_NEXT; clear: uwsgi_buffer_destroy(ub); if (tmp_qs) free(tmp_qs); return UWSGI_ROUTE_BREAK; }
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_ssh_routing(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { // ssh://username[:password]@127.0.0.1:2222/tmp/foo.txt,username[:password]@127.0.0.1:2222/tmp/foobis.txt char *remote_url = 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 = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub) { uwsgi_error("uwsgi_ssh_routing()/uwsgi_routing_translate()"); remote_url = ur->data; } else { remote_url = ub->buf; } remote_url = uwsgi_concat2(remote_url, ","); char *remote_pointer = remote_url; char *comma = NULL; struct uwsgi_ssh_mountpoint *usm = uwsgi_calloc(sizeof(struct uwsgi_ssh_mountpoint)); int return_status = -1; while ((comma = strchr(remote_url, ',')) != NULL) { *comma = 0; if (uwsgi_ssh_url_parser(remote_url, &usm)) { uwsgi_log("[SSH] skipping malformed route %s\n", remote_url); return_status = 500; continue; } if (!(return_status = uwsgi_ssh_request_file( wsgi_req, usm->path, usm ))) { goto end; } else { uwsgi_log("[SSH] route %s to %s returned %d. Engaging fail-over mechanism (if any)...\n", usm->remote, usm->path, return_status); } remote_url = comma + 1; } switch (return_status) { case 404: uwsgi_404(wsgi_req); break; case 500: default: uwsgi_500(wsgi_req); } end: free(remote_pointer); uwsgi_buffer_destroy(ub); return UWSGI_OK; }
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_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_routing_func_rpc_blob(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_NEXT; // optimization if (!wsgi_req->headers_sent) { if (uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6)) {free(response) ; goto end;} if (uwsgi_response_add_connection_close(wsgi_req)) {free(response) ; goto end;} } uwsgi_response_write_body_do(wsgi_req, response, size); free(response); end: for(i=0;i<ur->custom;i++) { if (ubs[i] != NULL) { uwsgi_buffer_destroy(ubs[i]); } } return ret; }
int uwsgi_routing_func_static(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { 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, ur->data, ur->data_len); if (!ub) return UWSGI_ROUTE_BREAK; uwsgi_file_serve(wsgi_req, ub->buf, ub->pos, NULL, 0, 1); uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_BREAK; }
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; }
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_routing_func_http(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { // mark a route request wsgi_req->via = UWSGI_VIA_ROUTE; // get the http address from the route char *addr = ur->data; struct uwsgi_buffer *ub_url = NULL; if (ur->data3_len) { char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); ub_url = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data3, ur->data3_len); if (!ub_url) return UWSGI_ROUTE_BREAK; } // convert the wsgi_request to an http proxy request struct uwsgi_buffer *ub = uwsgi_to_http(wsgi_req, ur->data2, ur->data2_len, ub_url ? ub_url->buf : NULL, ub_url ? ub_url->pos : 0); if (!ub) { if (ub_url) uwsgi_buffer_destroy(ub_url); uwsgi_log("unable to generate http request for %s\n", addr); return UWSGI_ROUTE_NEXT; } if (ub_url) uwsgi_buffer_destroy(ub_url); // amount of body to send size_t remains = wsgi_req->post_cl - wsgi_req->proto_parser_remains; // append remaining body... if (wsgi_req->proto_parser_remains > 0) { if (uwsgi_buffer_append(ub, wsgi_req->proto_parser_remains_buf, wsgi_req->proto_parser_remains)) { uwsgi_buffer_destroy(ub); uwsgi_log("unable to generate http request for %s\n", addr); return UWSGI_ROUTE_NEXT; } wsgi_req->proto_parser_remains = 0; } // ok now if have offload threads, directly use them if (!wsgi_req->post_file && !ur->custom && wsgi_req->socket->can_offload) { // append buffered body if (uwsgi.post_buffering > 0 && wsgi_req->post_cl > 0) { if (uwsgi_buffer_append(ub, wsgi_req->post_buffering_buf, wsgi_req->post_cl)) { uwsgi_buffer_destroy(ub); uwsgi_log("unable to generate http request for %s\n", addr); return UWSGI_ROUTE_NEXT; } } if (!uwsgi_offload_request_net_do(wsgi_req, addr, ub)) { wsgi_req->via = UWSGI_VIA_OFFLOAD; wsgi_req->status = 202; return UWSGI_ROUTE_BREAK; } } if (uwsgi_proxy_nb(wsgi_req, addr, ub, remains, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT])) { uwsgi_log("error routing request to http server %s\n", addr); } uwsgi_buffer_destroy(ub); return UWSGI_ROUTE_BREAK; }
static int uwsgi_routing_func_fcgi(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { struct uwsgi_buffer *ub = NULL, *headers = NULL; int ret = UWSGI_ROUTE_BREAK; int inbody = 0; // mark a route request wsgi_req->via = UWSGI_VIA_ROUTE; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub_addr = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub_addr) return UWSGI_ROUTE_BREAK; // convert the wsgi_request to an fcgi request ub = uwsgi_to_fastcgi(wsgi_req, ur->custom ? FCGI_AUTHORIZER : FCGI_RESPONDER); if (!ub) { uwsgi_log("unable to generate fcgi request for %s\n", ub_addr->buf); uwsgi_buffer_destroy(ub_addr); return UWSGI_ROUTE_BREAK; } int fd = 0; fd = fcgi_send(wsgi_req, ub_addr->buf, ub, uwsgi.socket_timeout); uwsgi_buffer_destroy(ub); ub = NULL; if (fd == -1) { uwsgi_log("error routing request to fcgi server %s\n", ub_addr->buf); goto end; } headers = uwsgi_buffer_new(uwsgi.page_size); char buf[8192]; char *ptr = buf;//, *rptr = NULL; ssize_t left = 0, n = 0, p = 0; int oversized = 0, done = 0; for (;;) { int r = uwsgi_waitfd(fd, uwsgi.socket_timeout); if (r <= 0) goto end; ssize_t rlen = 0; /* Amount left in buffer is not a full record header, so we * need to fudge the next read to append to the current buffer. */ if ((sizeof(buf) - (ptr - buf) - left) < 8) { memmove(buf, ptr, left); ptr = buf; } if ((!done || !left) && (sizeof(buf) - (ptr - buf) - left) > 0) { rlen = read(fd, ptr + left, sizeof(buf) - (ptr - buf) - left); if (rlen < 0) break; if (rlen == 0) done = 1; } if (done && !left) { uwsgi_log("[fastcgi] %s: truncated response\n", ub_addr->buf); goto end; } if (oversized) { /* n more bytes left in stdout record */ if (uwsgi_response_write_body_do(wsgi_req, (char *) ptr, n > rlen ? rlen : n)) goto end; if (n > rlen) { n -= rlen; ptr = buf; left = 0; continue; } else if (n == rlen) { oversized = 0; left = 0; ptr = buf; continue; } else { ptr += n; left = rlen - n; oversized = 0; continue; } } else { left += rlen; } while (left >= 8 && !oversized) { if (p) { if (left >= p) { left -= p; ptr += p; p = 0; continue; } } if (ptr[0] != 1) { /* version */ uwsgi_log("[fastcgi] %s: unexpected protocol version %u\n", ub_addr->buf, (unsigned int) ptr[0]); goto end; } if (ptr[2] != 0 || ptr[3] != 1) { /* reqid */ uwsgi_log("[fastcgi] %s: unexpected request id %d\n", ub_addr->buf, (int) ptr[3]); goto end; } n = (int)((unsigned char *)ptr)[4] << 8 | (int)((unsigned char *)ptr)[5]; p = (int)((unsigned char *)ptr)[6]; int type = ptr[1]; ptr += 8; left -= 8; switch (type) { case FCGI_END_REQUEST: break; case FCGI_STDERR: uwsgi_log("[fastcgi] %s: stderr: %*s\n", ub_addr->buf, (int) (n > left ? left : n), ptr); if ((n + p) > left) { uwsgi_log("[fastcgi] %s: short record, (%d + %d) < %d\n", ub_addr->buf, (int) n, (int) p, (int) left); goto end; } ptr += (n + p); left -= (n + p); break; case FCGI_STDOUT: if (n == 0) goto end; if (!inbody) { ssize_t now = n < left ? n : left; if (uwsgi_buffer_append(headers, (char *) ptr, now)) goto end; // check if we have a full HTTP response if (uwsgi_is_full_http(headers)) { inbody = 1; if (ur->custom && http_status_code(headers->buf, headers->pos) == 200) { ret = UWSGI_ROUTE_NEXT; /* XXX - add Variable headers */ goto end; } else { uwsgi_blob_to_response(wsgi_req, headers->buf, headers->pos); } uwsgi_buffer_destroy(headers); headers = NULL; } else { /* we can't buffer > sizeof(buf) of headers - shouldn't be * needed anyway. */ if (n > left) { uwsgi_log("[fastcgi] %s: headers too long (%d)\n", ub_addr->buf, (int) n); goto end; } } ptr += now; left -= now; n -= now; } if (n) { ssize_t nleft = n > left ? left : n; /* min(left in buffer, record size) */ if (uwsgi_response_write_body_do(wsgi_req, (char *) ptr, nleft)) goto end; n -= nleft; left -= nleft; ptr += nleft; if (n > left) { /* more data in this record */ oversized = 1; left = 0; ptr = buf; continue; } } break; default: uwsgi_log("[fastcgi] %s: unknown record type %d\n", ub_addr->buf, (int) ptr[1]); goto end; } } if (left == 0) ptr = buf; } end: if (fd) close(fd); if (ub) uwsgi_buffer_destroy(ub); if (ub_addr) uwsgi_buffer_destroy(ub_addr); if (headers) uwsgi_buffer_destroy(headers); return ret; }
// "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_routing_func_http(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { struct uwsgi_buffer *ub = NULL; // mark a route request wsgi_req->via = UWSGI_VIA_ROUTE; char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); struct uwsgi_buffer *ub_addr = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data, ur->data_len); if (!ub_addr) return UWSGI_ROUTE_BREAK; struct uwsgi_buffer *ub_url = NULL; if (ur->data3_len) { ub_url = uwsgi_routing_translate(wsgi_req, ur, *subject, *subject_len, ur->data3, ur->data3_len); if (!ub_url) { uwsgi_buffer_destroy(ub_addr); return UWSGI_ROUTE_BREAK; } } // convert the wsgi_request to an http proxy request if (ur->custom & 0x02) { ub = uwsgi_buffer_new(uwsgi.page_size); } else if (ur->custom & 0x04) { ub = uwsgi_to_http_dumb(wsgi_req, ur->data2, ur->data2_len, ub_url ? ub_url->buf : NULL, ub_url ? ub_url->pos : 0); } else { ub = uwsgi_to_http(wsgi_req, ur->data2, ur->data2_len, ub_url ? ub_url->buf : NULL, ub_url ? ub_url->pos : 0); } if (!ub) { if (ub_url) uwsgi_buffer_destroy(ub_url); uwsgi_log("unable to generate http request for %s\n", ub_addr->buf); uwsgi_buffer_destroy(ub_addr); return UWSGI_ROUTE_NEXT; } if (ub_url) uwsgi_buffer_destroy(ub_url); // amount of body to send size_t remains = wsgi_req->post_cl - wsgi_req->proto_parser_remains; // append remaining body... if (wsgi_req->proto_parser_remains > 0) { if (uwsgi_buffer_append(ub, wsgi_req->proto_parser_remains_buf, wsgi_req->proto_parser_remains)) { uwsgi_buffer_destroy(ub); uwsgi_log("unable to generate http request for %s\n", ub_addr->buf); uwsgi_buffer_destroy(ub_addr); return UWSGI_ROUTE_NEXT; } wsgi_req->post_pos += wsgi_req->proto_parser_remains; wsgi_req->proto_parser_remains = 0; } // ok now if have offload threads, directly use them if (!wsgi_req->post_file && !(ur->custom & 0x01) && wsgi_req->socket->can_offload) { // append buffered body if (uwsgi.post_buffering > 0 && wsgi_req->post_cl > 0) { if (uwsgi_buffer_append(ub, wsgi_req->post_buffering_buf, wsgi_req->post_cl)) { uwsgi_buffer_destroy(ub); uwsgi_log("unable to generate http request for %s\n", ub_addr->buf); uwsgi_buffer_destroy(ub_addr); return UWSGI_ROUTE_NEXT; } } // if we have a CONNECT request, let's confirm it to the client if (ur->custom & 0x02) { if (uwsgi_response_prepare_headers(wsgi_req, "200 Connection established", 26)) goto end; // no need to check for return value uwsgi_response_write_headers_do(wsgi_req); } if (!uwsgi_offload_request_net_do(wsgi_req, ub_addr->buf, ub)) { wsgi_req->via = UWSGI_VIA_OFFLOAD; wsgi_req->status = 202; uwsgi_buffer_destroy(ub_addr); return UWSGI_ROUTE_BREAK; } } if (uwsgi_proxy_nb(wsgi_req, ub_addr->buf, ub, remains, uwsgi.socket_timeout)) { uwsgi_log("error routing request to http server %s\n", ub_addr->buf); } end: uwsgi_buffer_destroy(ub); uwsgi_buffer_destroy(ub_addr); 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; }
static int uwsgi_routing_func_hash(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { struct uwsgi_router_hash_conf *urhc = (struct uwsgi_router_hash_conf *) ur->data2; struct uwsgi_hash_algo *uha = uwsgi_hash_algo_get(urhc->algo); if (!uha) { uwsgi_log("[uwsgi-hash-router] unable to find hash algo \"%s\"\n", urhc->algo); return UWSGI_ROUTE_BREAK; } 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, urhc->key, urhc->key_len); if (!ub) return UWSGI_ROUTE_BREAK; uint32_t h = uha->func(ub->buf, ub->pos); uwsgi_buffer_destroy(ub); // now count the number of items uint32_t items = 1; size_t i, ilen = urhc->items_len; for(i=0; i<ilen; i++) { if (urhc->items[i] == ';') items++; } // skip last semicolon if (urhc->items[ilen-1] == ';') items--; uint32_t hashed_result = h % items; uint32_t found = 0; char *value = urhc->items; uint16_t vallen = 0; for(i=0; i<ilen; i++) { if (!value) { value = urhc->items + i; } if (urhc->items[i] == ';') { if (found == hashed_result) { vallen = (urhc->items+i) - value; break; } value = NULL; found++; } } if (vallen == 0) { // first item if (hashed_result == 0) { value = urhc->items; vallen = urhc->items_len; } // last item else { vallen = (urhc->items + urhc->items_len) - value; } } if (!vallen) { uwsgi_log("[uwsgi-hash-router] BUG !!! unable to hash items\n"); return UWSGI_ROUTE_BREAK; } if (!uwsgi_req_append(wsgi_req, urhc->var, urhc->var_len, value, vallen)) { uwsgi_log("[uwsgi-hash-router] unable to append hash var to the request\n"); return UWSGI_ROUTE_BREAK; } return UWSGI_ROUTE_NEXT; }
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; }