// destroy a peer int uwsgi_cr_peer_del(struct corerouter_peer *peer) { // first of all check if we need to run a flush procedure if (peer->flush && !peer->is_flushing) { peer->is_flushing = 1; // on success, suspend the execution if (peer->flush(peer) > 0) return -1; } struct corerouter_peer *prev = peer->prev; struct corerouter_peer *next = peer->next; if (prev) { prev->next = peer->next; } if (next) { next->prev = peer->prev; } if (peer == peer->session->peers) { peer->session->peers = peer->next; } uwsgi_cr_peer_reset(peer); if (peer->in) { uwsgi_buffer_destroy(peer->in); } // main_peer bring the output buffer from backend peers if (peer->out && peer->out_need_free) { uwsgi_buffer_destroy(peer->out); } free(peer); return 0; }
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; }
//each protocol has its header generator int uwsgi_response_add_header(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *value, uint16_t value_len) { if (wsgi_req->headers_sent || wsgi_req->headers_size || wsgi_req->response_size || wsgi_req->write_errors) return -1; struct uwsgi_string_list *rh = uwsgi.remove_headers; while(rh) { if (!uwsgi_strnicmp(key, key_len, rh->value, rh->len)) { return 0; } rh = rh->next; } rh = wsgi_req->remove_headers; while(rh) { if (!uwsgi_strnicmp(key, key_len, rh->value, rh->len)) { return 0; } rh = rh->next; } if (!wsgi_req->headers) { wsgi_req->headers = uwsgi_buffer_new(uwsgi.page_size); wsgi_req->headers->limit = UMAX16; } struct uwsgi_buffer *hh = wsgi_req->socket->proto_add_header(wsgi_req, key, key_len, value, value_len); if (!hh) { wsgi_req->write_errors++ ; return -1;} if (uwsgi_buffer_append(wsgi_req->headers, hh->buf, hh->pos)) goto error; wsgi_req->header_cnt++; uwsgi_buffer_destroy(hh); return 0; error: uwsgi_buffer_destroy(hh); wsgi_req->write_errors++; return -1; }
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; }
// 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; }
// 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; }
// destroy a peer void uwsgi_cr_peer_del(struct corerouter_peer *peer) { struct corerouter_peer *prev = peer->prev; struct corerouter_peer *next = peer->next; if (prev) { prev->next = peer->next; } if (next) { next->prev = peer->prev; } if (peer == peer->session->peers) { peer->session->peers = peer->next; } uwsgi_cr_peer_reset(peer); if (peer->in) { uwsgi_buffer_destroy(peer->in); } // main_peer bring the output buffer from backend peers if (peer->out && peer->out_need_free) { uwsgi_buffer_destroy(peer->out); } free(peer); }
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_cache(struct wsgi_request *wsgi_req, struct uwsgi_route *ur){ struct uwsgi_router_cache_conf *urcc = (struct uwsgi_router_cache_conf *) ur->data2; if (!uwsgi.cache_max_items) return UWSGI_ROUTE_NEXT; char *c_k = NULL; uint16_t c_k_len = 0; struct uwsgi_buffer *ub = NULL; int k_need_free = 0; if (urcc->key) { char **subject = (char **) (((char *)(wsgi_req))+ur->subject); uint16_t *subject_len = (uint16_t *) (((char *)(wsgi_req))+ur->subject_len); c_k = uwsgi_regexp_apply_ovec(*subject, *subject_len, urcc->key, urcc->key_len, ur->ovector, ur->ovn); c_k_len = strlen(c_k); k_need_free = 1; } else { char **key = (char **) (((char *) wsgi_req) + urcc->var_offset); uint16_t *keylen = (uint16_t *) (((char *) wsgi_req) + urcc->var_offset_len); c_k = *key; c_k_len = *keylen; } uint64_t valsize = 0; char *value = uwsgi_cache_get(c_k, c_k_len, &valsize); if (value) { ub = uwsgi_buffer_new(uwsgi.page_size); if (urcc->type_num == 1) { wsgi_req->status = 200; if (uwsgi_buffer_append(ub, "HTTP/1.0 200 OK\r\nConnection: close\r\nContent-Type: ", 50)) goto error; if (uwsgi_buffer_append(ub, urcc->content_type, urcc->content_type_len)) goto error; if (uwsgi_buffer_append(ub, "\r\nContent-Length: ", 18 )) goto error; if (uwsgi_buffer_num64(ub, valsize)) goto error; if (uwsgi_buffer_append(ub, "\r\n\r\n", 4 )) goto error; wsgi_req->headers_size += wsgi_req->socket->proto_write_header(wsgi_req, ub->buf, ub->pos); uwsgi_buffer_destroy(ub); wsgi_req->header_cnt = 3; } // body only wsgi_req->response_size += wsgi_req->socket->proto_write(wsgi_req, value, valsize); if (k_need_free) free(c_k); if (ur->custom) return UWSGI_ROUTE_NEXT; return UWSGI_ROUTE_BREAK; } if (k_need_free) free(c_k); return UWSGI_ROUTE_NEXT; error: uwsgi_buffer_destroy(ub); if (k_need_free) free(c_k); return UWSGI_ROUTE_BREAK; }
struct uwsgi_buffer *uwsgi_exception_handler_object(struct wsgi_request *wsgi_req) { struct uwsgi_buffer *ub = uwsgi_buffer_new(4096); if (uwsgi_buffer_append_keyval(ub, "vars", 4, wsgi_req->buffer,wsgi_req->uh->pktsize)) goto error; if (uwsgi.p[wsgi_req->uh->modifier1]->backtrace) { struct uwsgi_buffer *bt = uwsgi.p[wsgi_req->uh->modifier1]->backtrace(wsgi_req); if (bt) { if (uwsgi_buffer_append_keyval(ub, "backtrace", 9, bt->buf, bt->pos)) { uwsgi_buffer_destroy(bt); goto error; } uwsgi_buffer_destroy(bt); } } if (uwsgi.p[wsgi_req->uh->modifier1]->exception_class) { struct uwsgi_buffer *ec = uwsgi.p[wsgi_req->uh->modifier1]->exception_class(wsgi_req); if (ec) { if (uwsgi_buffer_append_keyval(ub, "class", 5, ec->buf, ec->pos)) { uwsgi_buffer_destroy(ec); goto error; } uwsgi_buffer_destroy(ec); } } if (uwsgi.p[wsgi_req->uh->modifier1]->exception_msg) { struct uwsgi_buffer *em = uwsgi.p[wsgi_req->uh->modifier1]->exception_msg(wsgi_req); if (em) { if (uwsgi_buffer_append_keyval(ub, "msg", 3, em->buf, em->pos)) { uwsgi_buffer_destroy(em); goto error; } uwsgi_buffer_destroy(em); } } if (uwsgi.p[wsgi_req->uh->modifier1]->exception_repr) { struct uwsgi_buffer *er = uwsgi.p[wsgi_req->uh->modifier1]->exception_repr(wsgi_req); if (er) { if (uwsgi_buffer_append_keyval(ub, "repr", 4, er->buf, er->pos)) { uwsgi_buffer_destroy(er); goto error; } uwsgi_buffer_destroy(er); } } if (uwsgi_buffer_append_keynum(ub, "unix", 4, uwsgi_now())) goto error; if (uwsgi_buffer_append_keynum(ub, "wid", 3, uwsgi.mywid)) goto error; if (uwsgi_buffer_append_keynum(ub, "pid", 3, uwsgi.mypid)) goto error; if (uwsgi_buffer_append_keynum(ub, "core", 4, wsgi_req->async_id)) goto error; if (uwsgi_buffer_append_keyval(ub, "node", 4, uwsgi.hostname, uwsgi.hostname_len)) goto error; return ub; error: uwsgi_buffer_destroy(ub); return NULL; }
// status could be NNN or NNN message int uwsgi_response_prepare_headers(struct wsgi_request *wsgi_req, char *status, uint16_t status_len) { if (wsgi_req->headers_sent || wsgi_req->headers_size || wsgi_req->response_size || status_len < 3 || wsgi_req->write_errors) return -1; if (!wsgi_req->headers) { wsgi_req->headers = uwsgi_buffer_new(uwsgi.page_size); wsgi_req->headers->limit = UMAX16; } // reset the buffer (could be useful for rollbacks...) wsgi_req->headers->pos = 0; // reset headers count wsgi_req->header_cnt = 0; struct uwsgi_buffer *hh = NULL; wsgi_req->status = uwsgi_str3_num(status); #ifdef UWSGI_ROUTING // apply error routes if (uwsgi_apply_error_routes(wsgi_req) == UWSGI_ROUTE_BREAK) { // from now on ignore write body requests... wsgi_req->ignore_body = 1; return -1; } wsgi_req->is_error_routing = 0; #endif if (status_len <= 4) { char *new_sc = NULL; size_t new_sc_len = 0; uint16_t sc_len = 0; const char *sc = uwsgi_http_status_msg(status, &sc_len); if (sc) { new_sc = uwsgi_concat3n(status, 3, " ", 1, (char *)sc, sc_len); new_sc_len = 4+sc_len; } else { new_sc = uwsgi_concat2n(status, 3, " Unknown", 8); new_sc_len = 11; } hh = wsgi_req->socket->proto_prepare_headers(wsgi_req, new_sc, new_sc_len); free(new_sc); } else { hh = wsgi_req->socket->proto_prepare_headers(wsgi_req, status, status_len); } if (!hh) {wsgi_req->write_errors++; return -1;} if (uwsgi_buffer_append(wsgi_req->headers, hh->buf, hh->pos)) goto error; uwsgi_buffer_destroy(hh); return 0; error: uwsgi_buffer_destroy(hh); wsgi_req->write_errors++; return -1; }
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; }
void hr_session_ssl_close(struct corerouter_session *cs) { hr_session_close(cs); struct http_session *hr = (struct http_session *) cs; if (hr->ssl_client_dn) { OPENSSL_free(hr->ssl_client_dn); } if (hr->ssl_cc) { free(hr->ssl_cc); } if (hr->ssl_bio) { BIO_free(hr->ssl_bio); } if (hr->ssl_client_cert) { X509_free(hr->ssl_client_cert); } #ifdef UWSGI_SPDY if (hr->spdy_ping) { uwsgi_buffer_destroy(hr->spdy_ping); } if (hr->spdy) { deflateEnd(&hr->spdy_z_in); deflateEnd(&hr->spdy_z_out); } #endif // clear the errors (otherwise they could be propagated) hr_ssl_clear_errors(); SSL_free(hr->ssl); }
// cache command (uWSGI specific) static struct uwsgi_buffer *ssi_cmd_cache(struct wsgi_request *wsgi_req, struct uwsgi_ssi_arg *argv, int argc) { size_t var_len = 0; char *var = uwsgi_ssi_get_arg(argv, argc, "key", 3, &var_len); if (!var || var_len == 0) return NULL; size_t cache_len = 0; char *cache = uwsgi_ssi_get_arg(argv, argc, "name", 4, &cache_len); char *cache_name = NULL; if (cache && cache_len) { cache_name = uwsgi_concat2n(cache, cache_len, "", 0); } uint64_t rlen = 0; char *value = uwsgi_cache_magic_get(var, var_len, &rlen, NULL, cache_name); if (cache_name) free(cache_name); struct uwsgi_buffer *ub = NULL; if (value) { ub = uwsgi_buffer_new(rlen); if (uwsgi_buffer_append(ub, value, rlen)) { free(value); uwsgi_buffer_destroy(ub); return NULL; } free(value); } return ub; }
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; }
void hr_session_ssl_close(struct corerouter_session *cs) { hr_session_close(cs); struct http_session *hr = (struct http_session *) cs; if (hr->ssl_client_dn) { OPENSSL_free(hr->ssl_client_dn); } if (hr->ssl_cc) { free(hr->ssl_cc); } if (hr->ssl_bio) { BIO_free(hr->ssl_bio); } if (hr->ssl_client_cert) { X509_free(hr->ssl_client_cert); } #ifdef UWSGI_SPDY if (hr->spdy_ping) { uwsgi_buffer_destroy(hr->spdy_ping); } if (hr->spdy) { deflateEnd(&hr->spdy_z_in); deflateEnd(&hr->spdy_z_out); } #endif SSL_free(hr->ssl); }
static void stats_pusher_dogstatsd(struct uwsgi_stats_pusher_instance *uspi, time_t now, char *json, size_t json_len) { if (!uspi->configured) { struct dogstatsd_node *sn = uwsgi_calloc(sizeof(struct dogstatsd_node)); char *comma = strchr(uspi->arg, ','); if (comma) { sn->prefix = comma+1; sn->prefix_len = strlen(sn->prefix); *comma = 0; } else { sn->prefix = "uwsgi"; sn->prefix_len = 5; } char *colon = strchr(uspi->arg, ':'); if (!colon) { uwsgi_log("invalid dd address %s\n", uspi->arg); if (comma) *comma = ','; free(sn); return; } sn->addr_len = socket_to_in_addr(uspi->arg, colon, 0, &sn->addr.sa_in); sn->fd = socket(AF_INET, SOCK_DGRAM, 0); if (sn->fd < 0) { uwsgi_error("stats_pusher_dogstatsd()/socket()"); if (comma) *comma = ','; free(sn); return; } uwsgi_socket_nb(sn->fd); if (comma) *comma = ','; uspi->data = sn; uspi->configured = 1; } // we use the same buffer for all of the packets struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); struct uwsgi_metric *um = uwsgi.metrics; while(um) { uwsgi_rlock(uwsgi.metrics_lock); // ignore return value if (um->type == UWSGI_METRIC_GAUGE) { dogstatsd_send_metric(ub, uspi, um->name, um->name_len, *um->value, "|g"); } else { dogstatsd_send_metric(ub, uspi, um->name, um->name_len, *um->value, "|c"); } uwsgi_rwunlock(uwsgi.metrics_lock); if (um->reset_after_push){ uwsgi_wlock(uwsgi.metrics_lock); *um->value = um->initial_value; uwsgi_rwunlock(uwsgi.metrics_lock); } um = um->next; } uwsgi_buffer_destroy(ub); }
//each protocol has its header generator static int uwsgi_response_add_header_do(struct wsgi_request *wsgi_req, char *key, uint16_t key_len, char *value, uint16_t value_len) { if (!wsgi_req->headers) { wsgi_req->headers = uwsgi_buffer_new(uwsgi.page_size); wsgi_req->headers->limit = UMAX16; } struct uwsgi_buffer *hh = wsgi_req->socket->proto_add_header(wsgi_req, key, key_len, value, value_len); if (!hh) { wsgi_req->write_errors++ ; return -1;} if (uwsgi_buffer_append(wsgi_req->headers, hh->buf, hh->pos)) goto error; wsgi_req->header_cnt++; uwsgi_buffer_destroy(hh); return 0; error: uwsgi_buffer_destroy(hh); wsgi_req->write_errors++; return -1; }
int uwsgi_routing_func_uwsgi_remote(struct wsgi_request *wsgi_req, struct uwsgi_route *ur) { struct uwsgi_header *uh = (struct uwsgi_header *) ur->data; char *addr = ur->data + sizeof(struct uwsgi_header); // mark a route request wsgi_req->status = -17; // append appid if (ur->data2_len > 0) { uwsgi_req_append(wsgi_req, "UWSGI_APPID", 11, ur->data2, ur->data2_len); } // ok now if have offload threads, directly use them if (wsgi_req->socket->can_offload) { struct uwsgi_buffer *ub = uwsgi_buffer_new(4 + wsgi_req->uh.pktsize); if (ub) { uh->pktsize = wsgi_req->uh.pktsize; if (uwsgi_buffer_append(ub, (char *) uh, 4)) goto bad; if (uwsgi_buffer_append(ub, wsgi_req->buffer, uh->pktsize)) goto bad; if (!uwsgi_offload_request_net_do(wsgi_req, addr, ub)) { wsgi_req->status = -30; return UWSGI_ROUTE_BREAK; } bad: uwsgi_buffer_destroy(ub); } } int uwsgi_fd = uwsgi_connect(addr, uwsgi.shared->options[UWSGI_OPTION_SOCKET_TIMEOUT], 0); if (uwsgi_fd < 0) { uwsgi_log("unable to connect to host %s\n", addr); return UWSGI_ROUTE_NEXT; } int post_fd = wsgi_req->poll.fd; if (wsgi_req->async_post) { post_fd = fileno((FILE*)wsgi_req->async_post); } if (uwsgi_send_message(uwsgi_fd, uh->modifier1, uh->modifier2, wsgi_req->buffer, wsgi_req->uh.pktsize, post_fd, wsgi_req->post_cl, 0) < 0) { uwsgi_log("unable to send uwsgi request to host %s", addr); return UWSGI_ROUTE_NEXT; } ssize_t ret = uwsgi_pipe(uwsgi_fd, wsgi_req->poll.fd, 0); if (ret > 0) { wsgi_req->response_size += ret; } else { uwsgi_log("unable to manage uwsgi route response for %s\n", addr); } close(uwsgi_fd); 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_websocket_send_do(struct wsgi_request *wsgi_req, char *msg, size_t len) { struct uwsgi_buffer *ub = uwsgi_websocket_message(msg, len); if (!ub) return -1; ssize_t ret = uwsgi_response_write_body_do(wsgi_req, ub->buf, ub->pos); uwsgi_buffer_destroy(ub); return ret; }
static struct uwsgi_buffer *uwsgi_ruby_exception_msg(struct wsgi_request *wsgi_req) { VALUE err = rb_errinfo(); VALUE e = rb_funcall(err, rb_intern("message"), 0, 0); struct uwsgi_buffer *ub = uwsgi_buffer_new(RSTRING_LEN(e)); if (uwsgi_buffer_append(ub, RSTRING_PTR(e), RSTRING_LEN(e))) { uwsgi_buffer_destroy(ub); return NULL; } return ub; }
static struct uwsgi_buffer *uwsgi_ruby_exception_class(struct wsgi_request *wsgi_req) { VALUE err = rb_errinfo(); VALUE e = rb_class_name(rb_class_of(err)); struct uwsgi_buffer *ub = uwsgi_buffer_new(RSTRING_LEN(e)); if (uwsgi_buffer_append(ub, RSTRING_PTR(e), RSTRING_LEN(e))) { uwsgi_buffer_destroy(ub); return NULL; } return ub; }
// this is the function called by all request plugins to send chunks to the client int uwsgi_response_write_body_do(struct wsgi_request *wsgi_req, char *buf, size_t len) { if (wsgi_req->write_errors) return -1; if (!wsgi_req->headers_sent) { int ret = uwsgi_response_write_headers_do(wsgi_req); if (ret == UWSGI_OK) goto sendbody; if (ret == UWSGI_AGAIN) return UWSGI_AGAIN; wsgi_req->write_errors++; return -1; } sendbody: if (len == 0) return UWSGI_OK; for(;;) { int ret = wsgi_req->socket->proto_write(wsgi_req, buf, len); if (ret < 0) { if (!uwsgi.ignore_write_errors) { uwsgi_error("uwsgi_response_write_body_do()"); } wsgi_req->write_errors++; return -1; } if (ret == UWSGI_OK) { break; } ret = uwsgi_wait_write_req(wsgi_req); if (ret < 0) { wsgi_req->write_errors++; return -1;} if (ret == 0) { uwsgi_log("uwsgi_response_write_body_do() TIMEOUT !!!\n"); wsgi_req->write_errors++; return -1; } } wsgi_req->response_size += wsgi_req->write_pos; // reset for the next write wsgi_req->write_pos = 0; // now we need to check if the chunk must be stored if (wsgi_req->cache_it) { if (!wsgi_req->cached_response) { wsgi_req->cached_response = uwsgi_buffer_new(len); } // if we are unable to append the buffer, we just stop caching it if (uwsgi_buffer_append(wsgi_req->cached_response, buf, len)) { uwsgi_buffer_destroy(wsgi_req->cache_it); wsgi_req->cache_it = NULL; } } return UWSGI_OK; }
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; }
// status could be NNN or NNN message int uwsgi_response_prepare_headers(struct wsgi_request *wsgi_req, char *status, uint16_t status_len) { if (wsgi_req->headers_sent || wsgi_req->headers_size || wsgi_req->response_size || status_len < 3 || wsgi_req->write_errors) return -1; if (!wsgi_req->headers) { wsgi_req->headers = uwsgi_buffer_new(uwsgi.page_size); wsgi_req->headers->limit = UMAX16; } // reset the buffer (could be useful for rollbacks...) wsgi_req->headers->pos = 0; struct uwsgi_buffer *hh = NULL; if (status_len <= 4) { char *new_sc = NULL; size_t new_sc_len = 0; uint16_t sc_len = 0; const char *sc = uwsgi_http_status_msg(status, &sc_len); if (sc) { new_sc = uwsgi_concat3n(status, 3, " ", 1, (char *)sc, sc_len); new_sc_len = 4+sc_len; } else { new_sc = uwsgi_concat2n(status, 3, " Unknown", 8); new_sc_len = 11; } hh = wsgi_req->socket->proto_prepare_headers(wsgi_req, new_sc, new_sc_len); free(new_sc); } else { hh = wsgi_req->socket->proto_prepare_headers(wsgi_req, status, status_len); } if (!hh) {wsgi_req->write_errors++; return -1;} if (uwsgi_buffer_append(wsgi_req->headers, hh->buf, hh->pos)) goto error; uwsgi_buffer_destroy(hh); wsgi_req->status = uwsgi_str3_num(status); return 0; error: uwsgi_buffer_destroy(hh); wsgi_req->write_errors++; return -1; }
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; }
static struct uwsgi_buffer *uwsgi_ruby_exception_repr(struct wsgi_request *wsgi_req) { struct uwsgi_buffer *ub_class = uwsgi_ruby_exception_class(wsgi_req); if (!ub_class) return NULL; struct uwsgi_buffer *ub_msg = uwsgi_ruby_exception_msg(wsgi_req); if (!ub_msg) { uwsgi_buffer_destroy(ub_class); return NULL; } struct uwsgi_buffer *ub = uwsgi_buffer_new(ub_class->pos + 3 + ub_msg->pos); if (uwsgi_buffer_append(ub, ub_msg->buf, ub_msg->pos)) goto error; if (uwsgi_buffer_append(ub, " (", 2)) goto error; if (uwsgi_buffer_append(ub, ub_class->buf, ub_class->pos)) goto error; if (uwsgi_buffer_append(ub, ")", 1)) goto error; uwsgi_buffer_destroy(ub_class); uwsgi_buffer_destroy(ub_msg); return ub; error: uwsgi_buffer_destroy(ub_class); uwsgi_buffer_destroy(ub_msg); uwsgi_buffer_destroy(ub); return NULL; }
// printenv command static struct uwsgi_buffer *ssi_cmd_printenv(struct wsgi_request *wsgi_req, struct uwsgi_ssi_arg *argv, int argc) { struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); int i; for (i = 0; i < wsgi_req->var_cnt; i += 2) { if (uwsgi_buffer_append(ub, wsgi_req->hvec[i].iov_base, wsgi_req->hvec[i].iov_len)) goto error; if (uwsgi_buffer_append(ub, "=", 1)) goto error; if (uwsgi_buffer_append(ub, wsgi_req->hvec[i+1].iov_base, wsgi_req->hvec[i+1].iov_len)) goto error; if (uwsgi_buffer_append(ub, "\n", 1)) goto error; } return ub; error: uwsgi_buffer_destroy(ub); return NULL; };