Esempio n. 1
0
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;
}
Esempio n. 2
0
// 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;
}
Esempio n. 3
0
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;
}
Esempio n. 4
0
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;

}
Esempio n. 5
0
File: ssi.c Progetto: Algy/uwsgi
// 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;
}
Esempio n. 6
0
//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;
}
Esempio n. 7
0
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;
}
Esempio n. 8
0
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);
}
Esempio n. 9
0
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;

}
Esempio n. 10
0
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;
}
Esempio n. 11
0
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;
}
Esempio n. 12
0
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;
}
Esempio n. 13
0
// 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;	
}
Esempio n. 14
0
File: writer.c Progetto: JuanS/uwsgi
// 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;
}
Esempio n. 15
0
File: ssi.c Progetto: Algy/uwsgi
// 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;
};
Esempio n. 16
0
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);
}
Esempio n. 17
0
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);
}
Esempio n. 18
0
File: writer.c Progetto: JuanS/uwsgi
//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;
}
Esempio n. 19
0
File: ssi.c Progetto: Algy/uwsgi
// 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;
};
Esempio n. 20
0
// 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;
}
Esempio n. 21
0
File: webdav.c Progetto: JuanS/uwsgi
/*
	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;
}
Esempio n. 22
0
// 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;
}
Esempio n. 23
0
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];
}
Esempio n. 24
0
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;
}
Esempio n. 25
0
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;
}
Esempio n. 26
0
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;
}
Esempio n. 27
0
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;
}
Esempio n. 28
0
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;
}
Esempio n. 29
0
File: webdav.c Progetto: JuanS/uwsgi
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);
}
Esempio n. 30
0
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;
}