void uwsgi_websockets_init() { uwsgi.websockets_pong = uwsgi_buffer_new(2); uwsgi_buffer_append(uwsgi.websockets_pong, "\x8A\0", 2); uwsgi.websockets_ping = uwsgi_buffer_new(2); uwsgi_buffer_append(uwsgi.websockets_ping, "\x89\0", 2); uwsgi.websockets_ping_freq = 30; uwsgi.websockets_pong_tolerance = 3; uwsgi.websockets_max_size = 1024; }
// add a new peer to the session struct corerouter_peer *uwsgi_cr_peer_add(struct corerouter_session *cs) { struct corerouter_peer *old_peers = NULL, *peers = cs->peers; while(peers) { old_peers = peers; peers = peers->next; } peers = uwsgi_calloc(sizeof(struct corerouter_peer)); peers->session = cs; peers->fd = -1; // create input buffer size_t bufsize = cs->corerouter->buffer_size; if (!bufsize) bufsize = uwsgi.page_size; peers->in = uwsgi_buffer_new(bufsize); // add timeout peers->current_timeout = cs->corerouter->socket_timeout; peers->timeout = cr_add_timeout(cs->corerouter, peers); peers->prev = old_peers; if (old_peers) { old_peers->next = peers; } else { cs->peers = peers; } return peers; }
static struct uwsgi_buffer *uwsgi_websocket_message(struct wsgi_request *wsgi_req, char *msg, size_t len, uint8_t opcode) { struct uwsgi_buffer *ub = wsgi_req->websocket_send_buf; if (!ub) { wsgi_req->websocket_send_buf = uwsgi_buffer_new(10 + len); ub = wsgi_req->websocket_send_buf; } else { // reset the buffer ub->pos = 0; } if (uwsgi_buffer_u8(ub, opcode)) goto error; if (len < 126) { if (uwsgi_buffer_u8(ub, len)) goto error; } else if (len <= (uint16_t) 0xffff) { if (uwsgi_buffer_u8(ub, 126)) goto error; if (uwsgi_buffer_u16be(ub, len)) goto error; } else { if (uwsgi_buffer_u8(ub, 127)) goto error; if (uwsgi_buffer_u64be(ub, len)) goto error; } if (uwsgi_buffer_append(ub, msg, len)) goto error; return ub; error: return NULL; }
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; }
// 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; }
//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; }
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; }
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); }
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_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; }
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; }
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; }
// 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; }
// 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; }
// 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; };
void uwsgi_send_subscription(char *udp_address, char *key, size_t keysize, uint8_t modifier1, uint8_t modifier2, uint8_t cmd, char *socket_name, char *sign) { if (socket_name == NULL && !uwsgi.sockets) return; if (!socket_name) { socket_name = uwsgi.sockets->name; } struct uwsgi_buffer *ub = uwsgi_buffer_new(4096); // make space for uwsgi header ub->pos = 4; if (uwsgi_buffer_append_keyval(ub, "key", 3, key, keysize)) goto end; if (uwsgi_buffer_append_keyval(ub, "address", 7, socket_name, strlen(socket_name))) goto end; if (uwsgi_buffer_append_keynum(ub, "modifier1", 9, modifier1)) goto end; if (uwsgi_buffer_append_keynum(ub, "modifier2", 9, modifier2)) goto end; if (uwsgi_buffer_append_keynum(ub, "cores", 5, uwsgi.numproc * uwsgi.cores)) goto end; if (uwsgi_buffer_append_keynum(ub, "load", 4, uwsgi.shared->load)) goto end; if (uwsgi.auto_weight) { if (uwsgi_buffer_append_keynum(ub, "weight", 6, uwsgi.numproc * uwsgi.cores )) goto end; } else { if (uwsgi_buffer_append_keynum(ub, "weight", 6, uwsgi.weight )) goto end; } #ifdef UWSGI_SSL if (sign) { if (uwsgi_buffer_append_keynum(ub, "unix", 4, (uwsgi_now() + (time_t) cmd) )) goto end; unsigned int signature_len = 0; char *signature = uwsgi_rsa_sign(sign, ub->buf + 4, ub->pos - 4, &signature_len); if (signature && signature_len > 0) { if (uwsgi_buffer_append_keyval(ub, "sign", 4, signature, signature_len)) { free(signature); goto end; } free(signature); } } #endif send_udp_message(224, cmd, udp_address, ub->buf, ub->pos - 4); end: uwsgi_buffer_destroy(ub); }
static void stats_pusher_socket(struct uwsgi_stats_pusher_instance *uspi, time_t now, char *json, size_t json_len) { if (!uspi->configured) { struct socket_node *sn = uwsgi_calloc(sizeof(struct socket_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; } sn->fd = uwsgi_socket_from_addr(&sn->addr, &sn->addr_len, uspi->arg, SOCK_DGRAM); if (sn->fd < -1) { 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); socket_send_metric(ub, uspi, um); 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; }
// echo command static struct uwsgi_buffer *ssi_cmd_echo(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, "var", 3, &var_len); if (!var || var_len == 0) return NULL; uint16_t rlen = 0; char *value = uwsgi_get_var(wsgi_req, var, var_len, &rlen); if (!value) return NULL; if (rlen == 0) return NULL; struct uwsgi_buffer *ub = uwsgi_buffer_new(rlen); if (uwsgi_buffer_append(ub, value, rlen)) { uwsgi_buffer_destroy(ub); return NULL; } return ub; };
// allocate a new session static int rawrouter_alloc_session(struct uwsgi_corerouter *ucr, struct uwsgi_gateway_socket *ugs, struct corerouter_session *cs, struct sockaddr *sa, socklen_t s_len) { // set default read hook cs->main_peer->last_hook_read = rr_read; // set close hook cs->close = rr_session_close; // set retry hook cs->retry = rr_retry; if (sa && sa->sa_family == AF_INET) { if (urr.xclient) { struct rawrouter_session *rr = (struct rawrouter_session *) cs; rr->xclient = uwsgi_buffer_new(13+sizeof(cs->client_address)+2); if (uwsgi_buffer_append(rr->xclient, "XCLIENT ADDR=", 13)) return -1; if (uwsgi_buffer_append(rr->xclient, cs->client_address, strlen(cs->client_address))) return -1; if (uwsgi_buffer_append(rr->xclient, "\r\n", 2)) return -1; } } // add a new peer struct corerouter_peer *peer = uwsgi_cr_peer_add(cs); // set default peer hook peer->last_hook_read = rr_instance_read; // use the address as hostname memcpy(peer->key, cs->ugs->name, cs->ugs->name_len); peer->key_len = cs->ugs->name_len; // the mapper hook if (ucr->mapper(ucr, peer)) { return -1; } if (peer->instance_address_len == 0) { return -1; } peer->can_retry = 1; cr_connect(peer, rr_instance_connected); return 0; }
/* OPTIONS: if it is a valid webdav resource add Dav: to the response header */ static int uwsgi_wevdav_manage_options(struct wsgi_request *wsgi_req) { uwsgi_response_prepare_headers(wsgi_req, "200 OK", 6); if (udav.add_option) { struct uwsgi_buffer *ub = uwsgi_buffer_new(uwsgi.page_size); if (uwsgi_buffer_append(ub, "1, 2, 3", 7)) goto end; struct uwsgi_string_list *usl = udav.add_option; while(usl) { if (uwsgi_buffer_append(ub, ", ", 2)) goto end; if (uwsgi_buffer_append(ub, usl->value, usl->len)) goto end; usl = usl->next; } uwsgi_response_add_header(wsgi_req, "Dav", 3, ub->buf, ub->pos); end: uwsgi_buffer_destroy(ub); } else { uwsgi_response_add_header(wsgi_req, "Dav", 3, "1, 2, 3", 7); } return UWSGI_OK; }
// 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; }
struct corerouter_session *corerouter_alloc_session(struct uwsgi_corerouter *ucr, struct uwsgi_gateway_socket *ugs, int new_connection, struct sockaddr *cr_addr, socklen_t cr_addr_len) { ucr->cr_table[new_connection] = uwsgi_calloc(ucr->session_size); ucr->cr_table[new_connection]->fd = new_connection; ucr->cr_table[new_connection]->instance_fd = -1; // map courerouter and socket ucr->cr_table[new_connection]->corerouter = ucr; ucr->cr_table[new_connection]->ugs = ugs; // set initial timeout ucr->cr_table[new_connection]->timeout = cr_add_timeout(ucr, ucr->cr_table[new_connection]); // create dynamic buffer ucr->cr_table[new_connection]->buffer = uwsgi_buffer_new(uwsgi.page_size); // here we prepare the real session and set the hooks ucr->alloc_session(ucr, ugs, ucr->cr_table[new_connection], cr_addr, cr_addr_len); return ucr->cr_table[new_connection]; }
static struct uwsgi_buffer *uwsgi_websockets_parse(struct wsgi_request *wsgi_req) { // de-mask buffer uint8_t *ptr = (uint8_t *) (wsgi_req->websocket_buf->buf + (wsgi_req->websocket_pktsize - wsgi_req->websocket_size)); size_t i; if (wsgi_req->websocket_has_mask) { uint8_t *mask = ptr-4; for(i=0;i<wsgi_req->websocket_size;i++) { ptr[i] = ptr[i] ^ mask[i%4]; } } struct uwsgi_buffer *ub = uwsgi_buffer_new(wsgi_req->websocket_size); if (uwsgi_buffer_append(ub, (char *) ptr, wsgi_req->websocket_size)) goto error; if (uwsgi_buffer_decapitate(wsgi_req->websocket_buf, wsgi_req->websocket_pktsize)) goto error; wsgi_req->websocket_phase = 0; wsgi_req->websocket_need = 2; return ub; error: uwsgi_buffer_destroy(ub); return NULL; }
static struct uwsgi_buffer *uwsgi_websocket_message(char *msg, size_t len) { struct uwsgi_buffer *ub = uwsgi_buffer_new(10 + len); if (uwsgi_buffer_u8(ub, 0x81)) goto error; if (len < 126) { if (uwsgi_buffer_u8(ub, len)) goto error; } else if (len <= (uint16_t) 0xffff) { if (uwsgi_buffer_u8(ub, 126)) goto error; if (uwsgi_buffer_u16be(ub, len)) goto error; } else { if (uwsgi_buffer_u8(ub, 127)) goto error; if (uwsgi_buffer_u64be(ub, len)) goto error; } if (uwsgi_buffer_append(ub, msg, len)) goto error; return ub; error: uwsgi_buffer_destroy(ub); return NULL; }
static struct uwsgi_buffer *uwsgi_ruby_backtrace(struct wsgi_request *wsgi_req) { VALUE err = rb_errinfo(); VALUE ary = rb_funcall(err, rb_intern("backtrace"), 0); int i; struct uwsgi_buffer *ub = uwsgi_buffer_new(4096); char *filename = NULL; char *function = NULL; for (i=0; i<RARRAY_LEN(ary); i++) { char *bt = RSTRING_PTR(RARRAY_PTR(ary)[i]); // ok let's start the C dance to parse the backtrace char *colon = strchr(bt, ':'); if (!colon) continue; filename = uwsgi_concat2n(bt, (int) (colon-bt), "", 0); uint16_t filename_len = colon-bt; colon++; if (*colon == 0) goto error; char *lineno_ptr = colon; colon = strchr(lineno_ptr, ':'); if (!colon) goto error; int64_t lineno = uwsgi_str_num(lineno_ptr, (int) (colon-lineno_ptr)); colon++; if (*colon == 0) goto error; colon = strchr(lineno_ptr, '`'); if (!colon) goto error; colon++; if (*colon == 0) goto error; char *function_ptr = colon; char *function_end = strchr(function_ptr, '\''); if (!function_end) goto error; function = uwsgi_concat2n(function_ptr, (int) (function_end-function_ptr), "", 0); uint16_t function_len = function_end-function_ptr; if (uwsgi_buffer_u16le(ub, filename_len)) goto error; if (uwsgi_buffer_append(ub, filename, filename_len)) goto error; if (uwsgi_buffer_append_valnum(ub, lineno)) goto error; if (uwsgi_buffer_u16le(ub, function_len)) goto error; if (uwsgi_buffer_append(ub, function, function_len)) goto error; // in ruby we do not have text/code nor custom if (uwsgi_buffer_u16le(ub, 0)) goto error; if (uwsgi_buffer_append(ub, "", 0)) goto error; if (uwsgi_buffer_u16le(ub, 0)) goto error; if (uwsgi_buffer_append(ub, "", 0)) goto error; free(filename); filename = NULL; free(function); function = NULL; } return ub; error: uwsgi_buffer_destroy(ub); if (filename) { free(filename); } if (function) { free(function); } return NULL; }
static struct uwsgi_buffer *uwsgi_websocket_recv_do(struct wsgi_request *wsgi_req, int nb) { if (!wsgi_req->websocket_buf) { // this buffer will be destroyed on connection close wsgi_req->websocket_buf = uwsgi_buffer_new(uwsgi.page_size); // need 2 byte header wsgi_req->websocket_need = 2; } for(;;) { size_t remains = wsgi_req->websocket_buf->pos; // i have data; if (remains >= wsgi_req->websocket_need) { switch(wsgi_req->websocket_phase) { // header case 0: uwsgi_websocket_parse_header(wsgi_req); wsgi_req->websocket_pktsize = 2 + (wsgi_req->websocket_has_mask*4); if (wsgi_req->websocket_size == 126) { wsgi_req->websocket_need += 2; wsgi_req->websocket_phase = 1; wsgi_req->websocket_pktsize += 2; } else if (wsgi_req->websocket_size == 127) { wsgi_req->websocket_need += 8; wsgi_req->websocket_phase = 1; wsgi_req->websocket_pktsize += 8; } else { wsgi_req->websocket_phase = 2; } break; // size case 1: if (wsgi_req->websocket_size == 126) { wsgi_req->websocket_size = uwsgi_be16(wsgi_req->websocket_buf->buf+2); } else if (wsgi_req->websocket_size == 127) { wsgi_req->websocket_size = uwsgi_be64(wsgi_req->websocket_buf->buf+2); } else { uwsgi_log("[uwsgi-websocket] BUG error in websocket parser\n"); return NULL; } if (wsgi_req->websocket_size > (uwsgi.websockets_max_size*1024)) { uwsgi_log("[uwsgi-websocket] invalid packet size received: %llu, max allowed: %llu\n", wsgi_req->websocket_size, uwsgi.websockets_max_size * 1024); return NULL; } wsgi_req->websocket_phase = 2; break; // mask check case 2: if (wsgi_req->websocket_has_mask) { wsgi_req->websocket_need += 4; wsgi_req->websocket_phase = 3; } else { wsgi_req->websocket_need += wsgi_req->websocket_size; wsgi_req->websocket_phase = 4; } break; // mask case 3: wsgi_req->websocket_pktsize += wsgi_req->websocket_size; wsgi_req->websocket_need += wsgi_req->websocket_size; wsgi_req->websocket_phase = 4; break; // message case 4: switch (wsgi_req->websocket_opcode) { // message case 0: case 1: case 2: return uwsgi_websockets_parse(wsgi_req); // close case 0x8: return NULL; // ping case 0x9: if (uwsgi_websockets_pong(wsgi_req)) { return NULL; } break; // pong case 0xA: wsgi_req->websocket_last_pong = uwsgi_now(); break; default: break; } // reset the status wsgi_req->websocket_phase = 0; wsgi_req->websocket_need = 2; // decapitate the buffer if (uwsgi_buffer_decapitate(wsgi_req->websocket_buf, wsgi_req->websocket_pktsize)) return NULL; break; // oops default: uwsgi_log("[uwsgi-websocket] BUG error in websocket parser\n"); return NULL; } } // need more data else { if (uwsgi_buffer_ensure(wsgi_req->websocket_buf, uwsgi.page_size)) return NULL; ssize_t len = uwsgi_websockets_recv_pkt(wsgi_req, nb); if (len <= 0) { if (nb == 1 && len == 0) { // return an empty buffer to signal blocking event return uwsgi_buffer_new(0); } return NULL; } // update buffer size wsgi_req->websocket_buf->pos+=len; } } return NULL; }
struct corerouter_session *corerouter_alloc_session(struct uwsgi_corerouter *ucr, struct uwsgi_gateway_socket *ugs, int new_connection, struct sockaddr *cr_addr, socklen_t cr_addr_len) { struct corerouter_session *cs = uwsgi_calloc(ucr->session_size); struct corerouter_peer *peer = uwsgi_calloc(sizeof(struct corerouter_peer)); // main_peer has only input buffer as output buffer is taken from backend peers size_t bufsize = ucr->buffer_size; if (!bufsize) bufsize = uwsgi.page_size; peer->in = uwsgi_buffer_new(bufsize); ucr->cr_table[new_connection] = peer; cs->main_peer = peer; peer->fd = new_connection; peer->session = cs; // map corerouter and socket cs->corerouter = ucr; cs->ugs = ugs; // set initial timeout (could be overridden) peer->current_timeout = ucr->socket_timeout; ucr->active_sessions++; // build the client address memcpy(&cs->client_sockaddr, cr_addr, cr_addr_len); switch(cr_addr->sa_family) { case AF_INET: if (inet_ntop(AF_INET, &cs->client_sockaddr.sa_in.sin_addr, cs->client_address, cr_addr_len) == NULL) { uwsgi_error("corerouter_alloc_session/inet_ntop()"); memcpy(cs->client_address, "0.0.0.0", 7); cs->client_port[0] = '0'; cs->client_port[1] = 0; } uwsgi_num2str2(cs->client_sockaddr.sa_in.sin_port, cs->client_port); break; #ifdef AF_INET6 case AF_INET6: if (inet_ntop(AF_INET6, &cs->client_sockaddr.sa_in6.sin6_addr, cs->client_address, cr_addr_len) == NULL) { uwsgi_error("corerouter_alloc_session/inet_ntop()"); memcpy(cs->client_address, "0.0.0.0", 7); cs->client_port[0] = '0'; cs->client_port[1] = 0; } uwsgi_num2str2(cs->client_sockaddr.sa_in6.sin6_port, cs->client_port); break; #endif default: memcpy(cs->client_address, "0.0.0.0", 7); cs->client_port[0] = '0'; cs->client_port[1] = 0; break; } // here we prepare the real session and set the hooks if (ucr->alloc_session(ucr, ugs, cs, cr_addr, cr_addr_len)) { corerouter_close_session(ucr, cs); cs = NULL; } else { // truly set the timeout peer->timeout = cr_add_timeout(ucr, ucr->cr_table[new_connection]); } return cs; }
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_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; }