void wcb_recv(EV_P_ ev_io *w, int tev) { client_t *c = aux_memberof(client_t, wev_recv, w); char buf [4096]; int nb = aux_unix_recv(w->fd, buf, 4096); double time = ev_now(loop) - c->ts; times_sum += time; times_count++; if (times_max < time) times_max = time; if (times_min > time) times_min = time; /* fprintf(stderr, "recv fd=%d %f (%d bytes) %.*s\n", w->fd, ev_now(loop) - c->ts, nb, nb, buf); */ /* if (nb != 57) fprintf(stderr, "recv error %d bytes\n", nb); */ if (0 > nb) { if (errno == EAGAIN) { return; } fprintf(stderr, "recv error fd=%d (%d: %s)\n", w->fd, errno, strerror(errno)); client_del(c); return; } }
static void ugh_subreq_wcb_recv(EV_P_ ev_io *w, int tev) { ugh_subreq_t *r = aux_memberof(ugh_subreq_t, wev_recv, w); /* errno = 0; */ int nb = aux_unix_recv(w->fd, r->buf_recv.data, r->buf_recv.size); log_debug("subreq recv: %d: %.*s", nb, nb, r->buf_recv.data); if (0 == nb) { if (r->content_length != UGH_RESPONSE_CLOSE_AFTER_BODY) { /* * NOTE: recv(2) will never fail with EPIPE, so I'm using it here * to get meaningful error message in ugh_subreq_del' */ log_warn("upstream prematurely closed connection"); ugh_subreq_del(r, UGH_UPSTREAM_FT_ERROR, EPIPE); } else { ugh_subreq_del(r, UGH_UPSTREAM_FT_OFF, 0); } return; } if (0 > nb) { if (EAGAIN == errno) { if (UGH_TIMEOUT_ONCE == r->timeout_type) { ev_timer_again(loop, &r->wev_timeout); } return; } ugh_subreq_del(r, UGH_UPSTREAM_FT_ERROR, errno); return; } r->buf_recv.data += nb; r->buf_recv.size -= nb; if (UGH_TIMEOUT_ONCE == r->timeout_type) { ev_timer_again(loop, &r->wev_timeout); } if (NULL == r->body.data) { int status = ugh_parser_subreq(r, r->buf_recv.data - nb, nb); if (UGH_AGAIN == status) { return; } if (UGH_ERROR == status) { ugh_subreq_del(r, UGH_UPSTREAM_FT_INVALID_HEADER, 0); return; } ugh_header_t *hdr_content_length = ugh_subreq_header_get_nt(r, "Content-Length"); if (0 != hdr_content_length->value.size) { r->content_length = atoi(hdr_content_length->value.data); if (r->content_length > r->buf_recv.size + (r->buf_recv.data - r->request_end)) { r->body.data = aux_pool_nalloc(r->c->pool, r->content_length); r->body.size = r->buf_recv.data - r->request_end; memcpy(r->body.data, r->request_end, r->body.size); r->buf_recv.data = r->body.data + r->body.size; r->buf_recv.size = r->content_length - r->body.size; } else { r->body.data = r->request_end; r->body.size = r->buf_recv.data - r->request_end; } } else { ugh_header_t *hdr_transfer_encoding = ugh_subreq_header_get_nt(r, "Transfer-Encoding"); if (7 == hdr_transfer_encoding->value.size && 0 == strncmp(hdr_transfer_encoding->value.data, "chunked", 7)) { r->content_length = UGH_RESPONSE_CHUNKED; r->chunk_body_size = UGH_CHUNKS_BUF; r->body.data = aux_pool_nalloc(r->c->pool, r->chunk_body_size); r->body.size = 0; char *next_chunk = r->request_end; for (;;) { status = ugh_parser_chunks(r, next_chunk, r->buf_recv.data - next_chunk); if (UGH_AGAIN == status) { r->buf_recv.size += r->buf_recv.data - r->request_end; r->buf_recv.data = r->request_end; r->chunk_start = 0; return; } if (UGH_ERROR == status) { ugh_subreq_del(r, UGH_UPSTREAM_FT_INVALID_HEADER, 0); return; } if (0 == r->chunk_size) { ugh_subreq_del(r, UGH_UPSTREAM_FT_OFF, 0); return; } size_t recv_len = r->buf_recv.data - r->chunk_start; if (r->chunk_size > recv_len) { ugh_subreq_copy_chunk(r, r->chunk_start, recv_len); r->chunk_size -= recv_len; r->buf_recv.size += r->buf_recv.data - r->request_end; r->buf_recv.data = r->request_end; r->chunk_start = r->buf_recv.data; break; } else { ugh_subreq_copy_chunk(r, r->chunk_start, r->chunk_size); next_chunk = r->chunk_start + r->chunk_size; r->chunk_size = 0; r->chunk_start = 0; } } } else /* http/1.0 close after body response */ { r->content_length = UGH_RESPONSE_CLOSE_AFTER_BODY; r->body.data = r->request_end; r->body.size = r->buf_recv.data - r->request_end; if (r->buf_recv.size == 0) { char *old_body = r->body.data; r->body.data = aux_pool_nalloc(r->c->pool, r->body.size * 2); memcpy(r->body.data, old_body, r->body.size); r->buf_recv.data = r->body.data + r->body.size; r->buf_recv.size = r->body.size; } } } } else if (r->content_length == UGH_RESPONSE_CHUNKED) { for (;;) { char *next_chunk = r->buf_recv.data - nb; if (r->chunk_start) { size_t recv_len = r->buf_recv.data - r->chunk_start; if (r->chunk_size > recv_len) { ugh_subreq_copy_chunk(r, r->chunk_start, recv_len); r->chunk_size -= recv_len; r->buf_recv.data -= nb; r->buf_recv.size += nb; r->chunk_start = r->buf_recv.data; break; } else { ugh_subreq_copy_chunk(r, r->chunk_start, r->chunk_size); next_chunk = r->chunk_start + r->chunk_size; r->chunk_size = 0; } } int status = ugh_parser_chunks(r, next_chunk, r->buf_recv.data - next_chunk); if (UGH_AGAIN == status) { r->buf_recv.data -= nb; r->buf_recv.size += nb; r->chunk_start = 0; return; } if (UGH_ERROR == status) { ugh_subreq_del(r, UGH_UPSTREAM_FT_INVALID_HEADER, 0); return; } if (0 == r->chunk_size) { ugh_subreq_del(r, UGH_UPSTREAM_FT_OFF, 0); } } } else if (r->content_length == UGH_RESPONSE_CLOSE_AFTER_BODY) { r->body.size += nb; if (r->buf_recv.size == 0) { char *old_body = r->body.data; r->body.data = aux_pool_nalloc(r->c->pool, r->body.size * 2); memcpy(r->body.data, old_body, r->body.size); r->buf_recv.data = r->body.data + r->body.size; r->buf_recv.size = r->body.size; } } else { r->body.size += nb; } if (r->body.size == r->content_length) { uint32_t ft_type = UGH_UPSTREAM_FT_OFF; switch (r->status) { case 400: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 401: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 402: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 403: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 404: ft_type = UGH_UPSTREAM_FT_HTTP_404; break; case 405: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 406: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 407: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 408: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 409: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 410: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 411: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 412: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 413: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 414: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 415: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 416: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 417: ft_type = UGH_UPSTREAM_FT_HTTP_4XX; break; case 500: ft_type = UGH_UPSTREAM_FT_HTTP_500; break; case 501: ft_type = UGH_UPSTREAM_FT_HTTP_5XX; break; case 502: ft_type = UGH_UPSTREAM_FT_HTTP_502; break; case 503: ft_type = UGH_UPSTREAM_FT_HTTP_503; break; case 504: ft_type = UGH_UPSTREAM_FT_HTTP_504; break; case 505: ft_type = UGH_UPSTREAM_FT_HTTP_5XX; break; case 506: ft_type = UGH_UPSTREAM_FT_HTTP_5XX; break; case 507: ft_type = UGH_UPSTREAM_FT_HTTP_5XX; break; } ugh_subreq_del(r, ft_type, 0); } }
void echo_client_wcb_recv(EV_P_ ev_io *w, int tev) { int nb; echo_client_t *c = aux_memberof(echo_client_t, wev_recv, w); int rem_size = c->to_send + TO_SEND_SIZE - (c->to_send_beg + c->to_send_size); if (rem_size < 32) { /* fprintf(stderr, "rem_size=%d, c->to_send_size=%u, fd=%d\n", rem_size, (unsigned) c->to_send_size, w->fd); */ memcpy(c->to_send, c->to_send_beg, c->to_send_size); c->to_send_beg = c->to_send; rem_size = TO_SEND_SIZE - c->to_send_size; /* fprintf(stderr, "rem_size=%d\n", rem_size); */ } nb = aux_unix_recv(w->fd, c->to_send_beg + c->to_send_size, rem_size); /* fprintf(stderr, "recv %d bytes (%d: %s) %.*s\n", nb, errno, strerror(errno), nb, buf); */ if (0 > nb) { if (EAGAIN == errno) { ev_timer_again(loop, &c->wev_timeout); return; } fprintf(stderr, "recv error fd=%d (%d: %s)\n", w->fd, errno, strerror(errno)); echo_client_del(c); return; } if (0 == nb) { /* fprintf(stderr, "recv done fd=%d\n", w->fd); */ /* echo_client_del(c); */ return; } c->to_send_size += nb; int sent_nb; sent_nb = aux_unix_send(w->fd, c->to_send_beg, c->to_send_size); /* nb = aux_unix_send(w->fd, OUTPUT, sizeof(OUTPUT) - 1); */ /* fprintf(stderr, "sent %d bytes (%d: %s)\n", nb, errno, strerror(errno)); */ if (0 > sent_nb) { if (EAGAIN == errno) { ev_io_start(loop, &c->wev_send); return; } fprintf(stderr, "send error fd=%d (%d: %s)\n", w->fd, errno, strerror(errno)); echo_client_del(c); return; } c->to_send_beg += sent_nb; c->to_send_size -= sent_nb; if (c->to_send_size > 0) { ev_io_start(loop, &c->wev_send); return; } #if 0 nb = aux_unix_send(w->fd, buf, nb); /* fprintf(stderr, "sent %d bytes (%d: %s)\n", nb, errno, strerror(errno)); */ if (0 > nb) { fprintf(stderr, "send error fd=%d (%d: %s)\n", w->fd, errno, strerror(errno)); echo_client_del(c); return; } ev_timer_again(loop, &c->wev_timeout); #endif }
static void ugh_client_wcb_recv(EV_P_ ev_io *w, int tev) { int nb; ugh_client_t *c = aux_memberof(ugh_client_t, wev_recv, w); nb = aux_unix_recv(w->fd, c->buf_recv.data, c->buf_recv.size); log_debug("client recv: %d: %.*s", nb, nb, c->buf_recv.data); if (0 == nb) { ugh_client_del(c); return; } if (0 > nb) { if (EAGAIN == errno) { ev_timer_again(loop, &c->wev_timeout); return; } ugh_client_del(c); return; } c->buf_recv.data += nb; c->buf_recv.size -= nb; ev_timer_again(loop, &c->wev_timeout); if (NULL == c->request_end) { int status = ugh_parser_client(c, c->buf_recv.data - nb, nb); if (UGH_AGAIN == status) { return; } if (UGH_HTTP_BAD_REQUEST <= status) { ugh_client_send(c, status); return; } if (UGH_HTTP_POST == c->method) { ugh_header_t *hdr_content_length = ugh_client_header_get_nt(c, "Content-Length"); if (0 != hdr_content_length->value.size) { c->content_length = atoi(hdr_content_length->value.data); if (c->content_length > (c->buf_recv.size + (c->buf_recv.data - c->request_end))) { c->body.data = aux_pool_nalloc(c->pool, c->content_length); c->body.size = c->buf_recv.data - c->request_end; memcpy(c->body.data, c->request_end, c->body.size); c->buf_recv.data = c->body.data + c->body.size; c->buf_recv.size = c->content_length - c->body.size; } else { c->body.data = c->request_end; c->body.size = c->buf_recv.data - c->request_end; } if (c->body.size < c->content_length) { return; } } } } else if (UGH_HTTP_POST == c->method) { c->body.size += nb; if (c->body.size < c->content_length) { return; } } ev_io_stop(loop, &c->wev_recv); ev_timer_stop(loop, &c->wev_timeout); #if 1 /* prepare post args */ ugh_header_t *hdr_content_type = ugh_client_header_get_nt(c, "Content-Type"); if (sizeof("application/x-www-form-urlencoded") - 1 == hdr_content_type->value.size && 0 == strncmp(hdr_content_type->value.data, "application/x-www-form-urlencoded", hdr_content_type->value.size)) { ugh_parser_client_body(c, c->body.data, c->body.size); } #endif #if 1 /* UGH_CORO ENABLE */ c->stack = aux_pool_malloc(c->pool, UGH_CORO_STACK); if (NULL == c->stack) { ugh_client_send(c, UGH_HTTP_INTERNAL_SERVER_ERROR); return; } coro_create(&c->ctx, ugh_client_ccb_handle, c, c->stack, UGH_CORO_STACK, &ctx_main); is_main_coro = 0; coro_transfer(&ctx_main, &c->ctx); is_main_coro = 1; #endif #if 0 /* UGH_CORO DISABLE */ ugh_client_ccb_handle(c); #endif }