static void cb_read(struct bufferevent *bev, void *arg) { struct request_ctx *req = arg; char *line; size_t n; if (req->read_state == READ_NONE) { req->read_state = READ_STATUS; } while (req->read_state == READ_STATUS || req->read_state == READ_HEADERS) { line = read_line(bev, &n); if (line == NULL) { return; } if (req->read_state == READ_STATUS) { verbose(VERBOSE, "%s(): status line: '%s'\n", __func__, line); parse_status(req, line, n); set_read_state(req, READ_HEADERS); } else { while (line && req->read_state == READ_HEADERS) { if (*line == '\0') { set_read_state(req, READ_BODY); } else { char *key, *val; verbose(VERBOSE, "%s(): header line '%s'\n", __func__, line); header_keyval(&key, &val, line); handle_header(req, key, val); free(line); line = read_line(bev, &n); } } } free(line); } while (req->read_state == READ_BODY && evbuffer_get_length(bufferevent_get_input(bev)) > 0) { drain_body(req, bev); } if (req->read_state == READ_DONE) { request_done(req, bev); } }
static void drain_body(struct request_ctx *req, struct bufferevent *bev) { struct evbuffer *buf; struct evbuffer *saved; int before, after; if (req->chunked && req->chunk_size == -1) { /* Transfer-Encoding: chunked but we don't have size yet. */ if (read_chunk_size(req, bev) != 0) { verbose(ERROR, "%s(): could not read chunk size!\n", __func__); } } buf = bufferevent_get_input(bev); saved = NULL; before = evbuffer_get_length(buf); if (req->chunked && req->chunk_size > 0 && req->chunk_left < before) { /* * Save the real buffer away and give the callback * a temporary one, just the chunk that remains. */ saved = buf; buf = evbuffer_new(); evbuffer_remove_buffer(saved, buf, req->chunk_left); before = evbuffer_get_length(buf); } req->cb_ops->read(buf, req->cb_arg); after = evbuffer_get_length(buf); req->consumed += before - after; req->chunk_left -= (before - after); if (req->chunk_size > 0 && req->chunk_left == 0) { /* We've consumed the whole chunk. * Signal that we need another one. */ req->chunk_size = -1; } if (saved != NULL) { /* saved is actually the buffer in bev */ evbuffer_prepend_buffer(saved, buf); evbuffer_free(buf); } if ((req->chunked && req->chunk_size == 0) || (req->content_length > 0 && req->consumed == req->content_length)) { set_read_state(req, READ_DONE); } }
void grpc_call_initial_metadata_complete(grpc_call_element *surface_element) { grpc_call *call = grpc_call_from_top_element(surface_element); set_read_state(call, READ_STATE_GOT_INITIAL_METADATA); }
void grpc_call_stream_closed(grpc_call_element *elem) { grpc_call *call = CALL_FROM_TOP_ELEM(elem); set_read_state(call, READ_STATE_STREAM_CLOSED); grpc_call_internal_unref(call, 0); }
void grpc_call_read_closed(grpc_call_element *elem) { set_read_state(CALL_FROM_TOP_ELEM(elem), READ_STATE_READ_CLOSED); }