void finalostream_send(h2o_ostream_t *_self, h2o_req_t *req, h2o_iovec_t *inbufs, size_t inbufcnt, h2o_send_state_t send_state) { struct st_h2o_http1_finalostream_t *self = (void *)_self; struct st_h2o_http1_conn_t *conn = (struct st_h2o_http1_conn_t *)req->conn; h2o_iovec_t *bufs = alloca(sizeof(h2o_iovec_t) * (inbufcnt + 1)); int bufcnt = 0; assert(self == &conn->_ostr_final); if (!self->sent_headers) { conn->req.timestamps.response_start_at = *h2o_get_timestamp(conn->super.ctx, NULL, NULL); /* build headers and send */ const char *connection = req->http1_is_persistent ? "keep-alive" : "close"; bufs[bufcnt].base = h2o_mem_alloc_pool( &req->pool, flatten_headers_estimate_size(req, conn->super.ctx->globalconf->server_name.len + strlen(connection))); bufs[bufcnt].len = flatten_headers(bufs[bufcnt].base, req, connection); ++bufcnt; self->sent_headers = 1; } memcpy(bufs + bufcnt, inbufs, sizeof(h2o_iovec_t) * inbufcnt); bufcnt += inbufcnt; if (send_state == H2O_SEND_STATE_ERROR) { conn->req.http1_is_persistent = 0; } if (bufcnt != 0) { h2o_socket_write(conn->sock, bufs, bufcnt, h2o_send_state_is_in_progress(send_state) ? on_send_next_push : on_send_complete); } else { on_send_complete(conn->sock, 0); } }
static h2o_iovec_t *send_data_push(h2o_http2_conn_t *conn, h2o_http2_stream_t *stream, h2o_iovec_t *bufs, size_t bufcnt, h2o_send_state_t send_state) { h2o_iovec_t dst; size_t max_payload_size; if ((max_payload_size = calc_max_payload_size(conn, stream)) == 0) goto Exit; /* reserve buffer and point dst to the payload */ dst.base = h2o_buffer_reserve(&conn->_write.buf, H2O_HTTP2_FRAME_HEADER_SIZE + max_payload_size).base + H2O_HTTP2_FRAME_HEADER_SIZE; dst.len = max_payload_size; /* emit data */ while (bufcnt != 0) { if (bufs->len != 0) break; ++bufs; --bufcnt; } while (bufcnt != 0) { size_t fill_size = sz_min(dst.len, bufs->len); memcpy(dst.base, bufs->base, fill_size); dst.base += fill_size; dst.len -= fill_size; bufs->base += fill_size; bufs->len -= fill_size; while (bufs->len == 0) { ++bufs; --bufcnt; if (bufcnt == 0) break; } if (dst.len == 0) break; } /* commit the DATA frame if we have actually emitted payload */ if (dst.len != max_payload_size || !h2o_send_state_is_in_progress(send_state)) { size_t payload_len = max_payload_size - dst.len; if (bufcnt != 0) { send_state = H2O_SEND_STATE_IN_PROGRESS; } commit_data_header(conn, stream, &conn->_write.buf, payload_len, send_state); } Exit: return bufs; }
static void do_send(h2o_ostream_t *_self, h2o_req_t *req, h2o_iovec_t *inbufs, size_t inbufcnt, h2o_send_state_t state) { if (inbufcnt == 0 && h2o_send_state_is_in_progress(state)) { h2o_ostream_send_next(_self, req, inbufs, inbufcnt, state); return; } struct st_compress_encoder_t *self = (void *)_self; h2o_iovec_t *outbufs; size_t outbufcnt; self->compressor->transform(self->compressor, inbufs, inbufcnt, state, &outbufs, &outbufcnt); h2o_ostream_send_next(&self->super, req, outbufs, outbufcnt, state); }
static void proceed_pull(struct st_h2o_http1_conn_t *conn, size_t nfilled) { h2o_iovec_t buf = {conn->_ostr_final.pull.buf, nfilled}; h2o_send_state_t send_state; if (buf.len < MAX_PULL_BUF_SZ) { h2o_iovec_t cbuf = {buf.base + buf.len, MAX_PULL_BUF_SZ - buf.len}; send_state = h2o_pull(&conn->req, conn->_ostr_final.pull.cb, &cbuf); if (send_state == H2O_SEND_STATE_ERROR) { conn->req.http1_is_persistent = 0; } buf.len += cbuf.len; } else { send_state = H2O_SEND_STATE_IN_PROGRESS; } /* write */ h2o_socket_write(conn->sock, &buf, 1, h2o_send_state_is_in_progress(send_state) ? on_send_next_pull : on_send_complete); }