static inline void start_receiving_response(nxd_http_client_proto* hcp, nxe_loop* loop) { nxe_istream_unset_ready(&hcp->data_out); nxe_unset_timer(loop, NXWEB_TIMER_WRITE, &hcp->timer_write); nxe_set_timer(loop, NXWEB_TIMER_READ, &hcp->timer_read); nxe_ostream_set_ready(loop, &hcp->data_in); hcp->state=HCP_WAITING_FOR_RESPONSE; }
void nxd_http_client_proto_rearm(nxd_http_client_proto* hcp) { assert(hcp->nxb); nxb_empty(hcp->nxb); nxp_free(hcp->nxb_pool, hcp->nxb); hcp->nxb=0; memset(&hcp->_req, 0, sizeof(hcp->_req)); hcp->_req.nxb=hcp->nxb; hcp->_req.host=0; hcp->resp.nxb=hcp->nxb; while (hcp->events_pub.sub) nxe_unsubscribe(&hcp->events_pub, hcp->events_pub.sub); if (hcp->req_body_in.pair) nxe_disconnect_streams(hcp->req_body_in.pair, &hcp->req_body_in); if (hcp->resp_body_out.pair) nxe_disconnect_streams(&hcp->resp_body_out, hcp->resp_body_out.pair); nxe_ostream_unset_ready(&hcp->req_body_in); nxe_istream_unset_ready(&hcp->resp_body_out); nxe_ostream_unset_ready(&hcp->data_in); nxe_istream_unset_ready(&hcp->data_out); }
static inline void wait_for_100_continue(nxd_http_client_proto* hcp, nxe_loop* loop) { nxe_istream_unset_ready(&hcp->data_out); nxe_unset_timer(loop, NXWEB_TIMER_WRITE, &hcp->timer_write); nxe_set_timer(loop, NXWEB_TIMER_100CONTINUE, &hcp->timer_100_continue); nxe_ostream_set_ready(loop, &hcp->data_in); hcp->receiving_100_continue=1; hcp->state=HCP_WAITING_FOR_RESPONSE; }
static inline void request_complete(nxd_http_client_proto* hcp, nxe_loop* loop) { nxe_publish(&hcp->events_pub, (nxe_data)NXD_HCP_REQUEST_COMPLETE); if (hcp->queued_error_message.i) nxe_publish(&hcp->events_pub, hcp->queued_error_message); nxe_ostream_unset_ready(&hcp->data_in); nxe_istream_unset_ready(&hcp->data_out); nxe_unset_timer(loop, NXWEB_TIMER_READ, &hcp->timer_read); nxe_set_timer(loop, NXWEB_TIMER_KEEP_ALIVE, &hcp->timer_keep_alive); hcp->request_complete=1; hcp->state=HCP_IDLE; hcp->request_count++; }
void nxd_rbuffer_read(nxd_rbuffer* rb, int size) { nxweb_log_debug("nxd_rbuffer_read"); if (size) { rb->read_ptr+=size; assert(rb->read_ptr <= rb->end_ptr); if (rb->read_ptr >= rb->end_ptr) rb->read_ptr=rb->start_ptr; rb->last_write=0; if (!rb->eof) { if (rb->data_in.super.loop) nxe_ostream_set_ready(rb->data_in.super.loop, &rb->data_in); else rb->data_in.ready=1; } if (rb->read_ptr==rb->write_ptr && !rb->eof) { // nxd_rbuffer_is_empty(rb) //nxweb_log_error("rb->read_ptr==rb->write_ptr && !rb->eof => closing rb[%p].data_out", rb); if (rb->data_out.super.loop) nxe_istream_unset_ready(&rb->data_out); else rb->data_out.ready=0; } } }
static nxe_size_t resp_body_out_read(nxe_istream* is, nxe_ostream* os, void* ptr, nxe_size_t size, nxe_flags_t* flags) { nxd_http_client_proto* hcp=(nxd_http_client_proto*)((char*)is-offsetof(nxd_http_client_proto, resp_body_out)); nxe_loop* loop=is->super.loop; if (hcp->request_complete) { nxweb_log_error("hcp->request_complete - resp_body_out_read() should not be called"); *flags|=NXEF_EOF; nxe_istream_unset_ready(is); return 0; } if (hcp->state!=HCP_RECEIVING_BODY) { nxe_istream_unset_ready(is); nxe_ostream_set_ready(loop, &hcp->data_in); // get notified when prev_is ready return 0; } nxe_size_t bytes_received=0; if (hcp->first_body_chunk) { nxe_size_t first_body_chunk_size=hcp->first_body_chunk_end-hcp->first_body_chunk; if (first_body_chunk_size<=size) { bytes_received=first_body_chunk_size; memcpy(ptr, hcp->first_body_chunk, bytes_received); hcp->first_body_chunk=0; hcp->first_body_chunk_end=0; } else { bytes_received=size; memcpy(ptr, hcp->first_body_chunk, size); hcp->first_body_chunk+=size; } hcp->resp.content_received+=bytes_received; if (hcp->response_body_complete) { // rearm connection request_complete(hcp, loop); nxe_istream_unset_ready(is); *flags|=NXEF_EOF; return bytes_received; } ptr+=bytes_received; size-=bytes_received; } if (size>0) { nxe_istream* prev_is=hcp->data_in.pair; if (prev_is) { nxe_size_t bytes_received2=0; nxe_flags_t rflags=0; if (prev_is->ready) bytes_received2=ISTREAM_CLASS(prev_is)->read(prev_is, &hcp->data_in, ptr, size, &rflags); if (!prev_is->ready) { nxe_istream_unset_ready(is); nxe_ostream_set_ready(loop, &hcp->data_in); // get notified when prev_is becomes ready again } if (hcp->resp.chunked_encoding) { int r=_nxweb_decode_chunked_stream(&hcp->resp.cdstate, ptr, &bytes_received2); hcp->resp.content_received+=bytes_received2; bytes_received+=bytes_received2; if (r<0) nxe_publish(&hcp->events_pub, (nxe_data)NXD_HCP_RESPONSE_CHUNKED_ENCODING_ERROR); else if (r>0) hcp->response_body_complete=1; } else { hcp->resp.content_received+=bytes_received2; bytes_received+=bytes_received2; if (hcp->resp.content_received >= hcp->resp.content_length && hcp->resp.content_length>=0) { hcp->response_body_complete=1; } } if (hcp->response_body_complete) { // rearm connection request_complete(hcp, loop); nxe_istream_unset_ready(is); *flags|=NXEF_EOF; return bytes_received; } } else { if (!prev_is) nxweb_log_error("no connected device for hcp->data_in"); nxe_istream_unset_ready(is); } } return bytes_received; }
static void data_out_do_write(nxe_istream* is, nxe_ostream* os) { nxd_http_client_proto* hcp=(nxd_http_client_proto*)((char*)is-offsetof(nxd_http_client_proto, data_out)); nxe_loop* loop=is->super.loop; nxe_unset_timer(loop, NXWEB_TIMER_WRITE, &hcp->timer_write); nxe_set_timer(loop, NXWEB_TIMER_WRITE, &hcp->timer_write); if (hcp->state==HCP_CONNECTING) { nxe_publish(&hcp->events_pub, (nxe_data)NXD_HCP_CONNECTED); if (hcp->req) hcp->state=HCP_SENDING_HEADERS; else { hcp->state=HCP_IDLE; nxe_set_timer(loop, NXWEB_TIMER_KEEP_ALIVE, &hcp->timer_keep_alive); nxe_istream_unset_ready(is); return; } } if (hcp->state==HCP_SENDING_HEADERS) { if (hcp->req_headers_ptr && *hcp->req_headers_ptr) { int size=strlen(hcp->req_headers_ptr); nxe_flags_t flags=0; int bytes_sent=OSTREAM_CLASS(os)->write(os, is, 0, (nxe_data)hcp->req_headers_ptr, size, &flags); hcp->req_headers_ptr+=bytes_sent; if (bytes_sent<size) return; } // all headers sent hcp->req_headers_ptr=0; if (!hcp->req->content_length) { // no request body => get response start_receiving_response(hcp, loop); return; } if (hcp->req->expect_100_continue) { nxe_istream_unset_ready(is); wait_for_100_continue(hcp, loop); return; } hcp->state=HCP_SENDING_BODY; } if (hcp->state==HCP_SENDING_BODY) { hcp->req_body_sending_started=1; nxe_istream* prev_is=hcp->req_body_in.pair; if (prev_is) { if (prev_is->ready) { hcp->req_body_in.ready=1; ISTREAM_CLASS(prev_is)->do_write(prev_is, &hcp->req_body_in); } if (!prev_is->ready) { nxe_istream_unset_ready(is); nxe_ostream_set_ready(loop, &hcp->req_body_in); // get notified when prev_is becomes ready again } } else { nxweb_log_error("no connected device for hcp->req_body_in"); nxe_istream_unset_ready(is); } } else { // wrong state nxweb_log_error("called data_out_do_write() at wrong HCP state %d", hcp->state); nxe_istream_unset_ready(is); } }