Example #1
0
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;
}
Example #2
0
static void accept_connection(nxe_loop* loop, nxweb_http_server_listening_socket* lsock) {
  //static int next_net_thread_idx=0;
  //nxweb_accept accept_msg;
  int client_fd;
  struct sockaddr_in client_addr;
  socklen_t client_len=sizeof(client_addr);
  nxe_unset_timer(loop, NXWEB_TIMER_ACCEPT_RETRY, &lsock->accept_retry_timer);
  while (!shutdown_in_progress) {
    client_fd=accept4(lsock->listen_source.fd, (struct sockaddr *)&client_addr, &client_len, SOCK_NONBLOCK);
    if (client_fd!=-1) {
      if (/*_nxweb_set_non_block(client_fd) ||*/ _nxweb_setup_client_socket(client_fd)) {
        _nxweb_close_bad_socket(client_fd);
        nxweb_log_error("failed to setup client socket");
        continue;
      }
      int lconf_idx=lsock->idx;
      nxweb_net_thread_data* tdata=(nxweb_net_thread_data*)((char*)(lsock-lconf_idx)-offsetof(nxweb_net_thread_data, listening_sock));
      nxweb_http_server_connection* conn=nxp_alloc(tdata->free_conn_pool);
      nxweb_http_server_connection_init(conn, tdata, lconf_idx);
      inet_ntop(AF_INET, &client_addr.sin_addr, conn->remote_addr, sizeof(conn->remote_addr));
      nxweb_http_server_connection_connect(conn, loop, client_fd);
    }
    else {
      if (errno!=EAGAIN) {
        nxweb_log_error("accept() failed %d", errno);
        // retry accept after timeout
        nxe_set_timer(loop, NXWEB_TIMER_ACCEPT_RETRY, &lsock->accept_retry_timer);
      }
      break;
    }
  }
}
Example #3
0
void nxd_http_client_proto_start_request(nxd_http_client_proto* hcp, nxweb_http_request* req) {
  //nxweb_http_request* resp=&hcp->resp;
  hcp->nxb=nxp_alloc(hcp->nxb_pool);
  nxb_init(hcp->nxb, NXWEB_CONN_NXB_SIZE);

  hcp->req=req;
  if (!req->nxb) req->nxb=hcp->nxb;
  if (!req->host) req->host=hcp->host;

  nxe_loop* loop=hcp->data_in.super.loop;
  hcp->req_headers_ptr=_nxweb_prepare_client_request_headers(req);
  //nxweb_log_error("REQ: %s", hcp->req_headers_ptr);
  if (!hcp->req_body_in.pair && req->content && req->content_length>0) {
    nxd_obuffer_init(&hcp->ob, req->content, req->content_length);
    nxe_connect_streams(loop, &hcp->ob.data_out, &hcp->req_body_in);
  }
  if (hcp->state==HCP_IDLE) hcp->state=HCP_SENDING_HEADERS;
  nxe_unset_timer(loop, NXWEB_TIMER_KEEP_ALIVE, &hcp->timer_keep_alive);
  hcp->req_body_sending_started=0;
  hcp->receiving_100_continue=0;
  hcp->request_complete=0;
  hcp->response_body_complete=0;
  hcp->queued_error_message.l=0;
  nxe_istream_set_ready(loop, &hcp->data_out);
}
Example #4
0
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;
}
Example #5
0
void nxd_http_client_proto_finalize(nxd_http_client_proto* hcp) {
  nxe_loop* loop=hcp->data_in.super.loop;
  nxe_unset_timer(loop, NXWEB_TIMER_KEEP_ALIVE, &hcp->timer_keep_alive);
  nxe_unset_timer(loop, NXWEB_TIMER_READ, &hcp->timer_read);
  nxe_unset_timer(loop, NXWEB_TIMER_WRITE, &hcp->timer_write);
  nxe_unset_timer(loop, NXWEB_TIMER_100CONTINUE, &hcp->timer_100_continue);
  if (hcp->data_error.pub) nxe_unsubscribe(hcp->data_error.pub, &hcp->data_error);
  while (hcp->events_pub.sub) nxe_unsubscribe(&hcp->events_pub, hcp->events_pub.sub);
  if (hcp->data_in.pair) nxe_disconnect_streams(hcp->data_in.pair, &hcp->data_in);
  if (hcp->data_out.pair) nxe_disconnect_streams(&hcp->data_out, hcp->data_out.pair);
  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);
  if (hcp->nxb) {
    nxb_empty(hcp->nxb);
    nxp_free(hcp->nxb_pool, hcp->nxb);
    hcp->nxb=0;
  }
}
Example #6
0
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++;
}
Example #7
0
static void nxweb_http_proxy_request_finalize(nxd_http_server_proto* hsp, void* req_data) {

  nxweb_log_debug("nxweb_http_proxy_request_finalize");

  nxweb_http_proxy_request_data* rdata=req_data;
  nxweb_http_server_connection* conn=rdata->conn;
  nxe_loop* loop=conn->tdata->loop;
  nxe_unset_timer(loop, NXWEB_TIMER_BACKEND, &rdata->timer_backend);
  if (rdata->rb_resp.data_in.pair) nxe_disconnect_streams(rdata->rb_resp.data_in.pair, &rdata->rb_resp.data_in);
  if (rdata->rb_resp.data_out.pair) nxe_disconnect_streams(&rdata->rb_resp.data_out, rdata->rb_resp.data_out.pair);
  if (rdata->rb_req.data_in.pair) nxe_disconnect_streams(rdata->rb_req.data_in.pair, &rdata->rb_req.data_in);
  if (rdata->rb_req.data_out.pair) nxe_disconnect_streams(&rdata->rb_req.data_out, rdata->rb_req.data_out.pair);
  if (rdata->proxy_events_sub.pub) nxe_unsubscribe(rdata->proxy_events_sub.pub, &rdata->proxy_events_sub);
  if (rdata->hpx) {
    nxd_http_proxy_pool_return(rdata->hpx, rdata->proxy_request_error);
    rdata->hpx=0;
  }
  if (rdata->rbuf) {
    if (rdata->rbuf) nxp_free(conn->tdata->free_rbuf_pool, rdata->rbuf);
    rdata->rbuf=0;
  }
}
Example #8
0
static nxe_ssize_t req_body_in_write(nxe_ostream* os, nxe_istream* is, int fd, nxe_data ptr, nxe_size_t size, nxe_flags_t* flags) {
  //nxweb_log_error("req_body_in_write(%d)", size);
  nxd_http_client_proto* hcp=(nxd_http_client_proto*)((char*)os-offsetof(nxd_http_client_proto, req_body_in));
  nxe_loop* loop=os->super.loop;
  if (hcp->state!=HCP_SENDING_BODY) {
    nxe_ostream_unset_ready(os);
    nxe_istream_set_ready(loop, &hcp->data_out); // get notified when next_os ready
    return 0;
  }
  hcp->req_body_sending_started=1;
  nxe_unset_timer(loop, NXWEB_TIMER_WRITE, &hcp->timer_write);
  nxe_ssize_t bytes_sent=0;
  if (size>0) {
    nxe_ostream* next_os=hcp->data_out.pair;
    if (next_os) {
      nxe_flags_t wflags=*flags;
      if (next_os->ready) bytes_sent=OSTREAM_CLASS(next_os)->write(next_os, &hcp->data_out, 0, (nxe_data)ptr, size, &wflags);
      if (!next_os->ready) {
        //nxweb_log_error("req_body_in_write(%d) - next_os unready", size);
        nxe_ostream_unset_ready(os);
        nxe_istream_set_ready(loop, &hcp->data_out); // get notified when next_os becomes ready again
      }
    }
    else {
      nxweb_log_error("no connected device for hcp->data_out");
      nxe_ostream_unset_ready(os);
    }
  }
  if (*flags&NXEF_EOF && bytes_sent==size) {
    // end of request => get response
    nxe_ostream_unset_ready(os);
    start_receiving_response(hcp, loop);
    return bytes_sent;
  }
  nxe_set_timer(loop, NXWEB_TIMER_WRITE, &hcp->timer_write);
  return bytes_sent;
}
Example #9
0
static void data_in_do_read(nxe_ostream* os, nxe_istream* is) {
  nxd_http_client_proto* hcp=(nxd_http_client_proto*)((char*)os-offsetof(nxd_http_client_proto, data_in));
  nxe_loop* loop=os->super.loop;
  if (hcp->state==HCP_WAITING_FOR_RESPONSE) {
    nxe_unset_timer(loop, NXWEB_TIMER_READ, &hcp->timer_read);
    nxe_unset_timer(loop, NXWEB_TIMER_100CONTINUE, &hcp->timer_100_continue);
    nxe_set_timer(loop, NXWEB_TIMER_READ, &hcp->timer_read);
    nxb_make_room(hcp->nxb, NXWEB_MAX_REQUEST_HEADERS_SIZE);
    hcp->state=HCP_RECEIVING_HEADERS;
  }

  if (hcp->state==HCP_RECEIVING_HEADERS) {
    int size;
    nxe_flags_t flags=0;
    void* ptr=nxb_get_room(hcp->nxb, &size);
    int bytes_received=ISTREAM_CLASS(is)->read(is, os, ptr, size, &flags);
    if (bytes_received) {
      nxb_blank_fast(hcp->nxb, bytes_received);
      int read_buf_size;
      char* read_buf=nxb_get_unfinished(hcp->nxb, &read_buf_size);
      char* end_of_headers;
      char* start_of_body;
      if ((end_of_headers=_nxweb_find_end_of_http_headers(read_buf, read_buf_size, &start_of_body))) {
        nxb_finish_stream(hcp->nxb, 0);
        memset(&hcp->resp, 0, sizeof(hcp->resp));
        hcp->resp.nxb=hcp->nxb;
        hcp->resp.cdstate.monitor_only=hcp->chunked_do_not_decode;
        if (_nxweb_parse_http_response(&hcp->resp, read_buf, end_of_headers)) {
          // bad response
          nxe_unset_timer(loop, NXWEB_TIMER_READ, &hcp->timer_read);
          nxe_ostream_unset_ready(os);
          nxe_publish(&hcp->events_pub, (nxe_data)NXD_HCP_BAD_RESPONSE);
          return;
        }
        if (hcp->receiving_100_continue) {
          hcp->receiving_100_continue=0;
          if (hcp->resp.status_code==100) {
            // back to sending request body
            nxe_ostream_unset_ready(&hcp->data_in);
            nxe_unset_timer(loop, NXWEB_TIMER_READ, &hcp->timer_read);
            nxe_set_timer(loop, NXWEB_TIMER_WRITE, &hcp->timer_write);
            nxe_istream_set_ready(loop, &hcp->data_out);
            hcp->state=HCP_SENDING_BODY;
            return;
          }
          else {
            nxe_publish(&hcp->events_pub, (nxe_data)NXD_HCP_NO_100CONTINUE);
          }
        }
        char* read_buf_end=read_buf+read_buf_size;
        if (start_of_body<read_buf_end) {
          hcp->first_body_chunk=start_of_body;
          hcp->first_body_chunk_end=read_buf_end;

          nxe_size_t first_body_chunk_size=hcp->first_body_chunk_end-hcp->first_body_chunk;
          if (hcp->resp.chunked_encoding) {
            int r=_nxweb_decode_chunked_stream(&hcp->resp.cdstate, hcp->first_body_chunk, &first_body_chunk_size);
            hcp->first_body_chunk_end=hcp->first_body_chunk+first_body_chunk_size;
            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 if (first_body_chunk_size >= hcp->resp.content_length && hcp->resp.content_length>=0) {
            hcp->response_body_complete=1;
          }
        }
        else {
          hcp->first_body_chunk=0;
          hcp->first_body_chunk_end=0;
        }
        nxe_ostream_unset_ready(os);
        nxe_publish(&hcp->events_pub, (nxe_data)NXD_HCP_RESPONSE_RECEIVED);
        if (hcp->resp.content_length && !hcp->req->head_method) { // is body expected?
          hcp->state=HCP_RECEIVING_BODY;
          nxe_istream_set_ready(loop, &hcp->resp_body_out);
          if (hcp->resp_body_out.pair) {
            nxe_ostream_set_ready(loop, os);
          }
        }
        else {
          // rearm connection
          request_complete(hcp, loop);
        }
      }
      else {
        if (read_buf_size>=NXWEB_MAX_REQUEST_HEADERS_SIZE) {
          // bad response (headers too large)
          nxe_unset_timer(loop, NXWEB_TIMER_READ, &hcp->timer_read);
          nxe_ostream_unset_ready(os);
          nxe_publish(&hcp->events_pub, (nxe_data)NXD_HCP_BAD_RESPONSE);
          return;
        }
      }
    }
  }
  else if (hcp->state==HCP_RECEIVING_BODY) {
    nxe_ostream* next_os=hcp->resp_body_out.pair;
    if (next_os) {
      if (next_os->ready) OSTREAM_CLASS(next_os)->do_read(next_os, &hcp->resp_body_out);
      if (!next_os->ready) {
        nxe_ostream_unset_ready(os);
        nxe_istream_set_ready(loop, &hcp->resp_body_out); // get notified when next_os becomes ready again
      }
    }
    else {
      nxweb_log_error("no connected device for hcp->resp_body_out");
      nxe_ostream_unset_ready(os);
    }
  }
}
Example #10
0
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);
  }
}
Example #11
0
static void nxweb_http_server_proxy_events_sub_on_message(nxe_subscriber* sub, nxe_publisher* pub, nxe_data data) {

  nxweb_log_debug("nxweb_http_server_proxy_events_sub_on_message");

  nxweb_http_proxy_request_data* rdata=(nxweb_http_proxy_request_data*)((char*)sub-offsetof(nxweb_http_proxy_request_data, proxy_events_sub));
  nxweb_http_server_connection* conn=rdata->conn;
  nxe_loop* loop=sub->super.loop;
  if (data.i==NXD_HCP_RESPONSE_RECEIVED) {
    nxe_unset_timer(loop, NXWEB_TIMER_BACKEND, &rdata->timer_backend);
    //nxweb_http_request* req=&conn->hsp.req;
    nxd_http_proxy* hpx=rdata->hpx;
    nxweb_http_response* presp=&hpx->hcp.resp;
    nxweb_http_response* resp=&conn->hsp._resp;
    resp->status=presp->status;
    resp->status_code=presp->status_code;
    resp->content_type=presp->content_type;
    resp->content_length=presp->content_length;
    if (resp->content_length<0) resp->chunked_autoencode=1; // re-encode chunked or until-close content
    resp->ssi_on=presp->ssi_on;
    resp->templates_on=presp->templates_on;
    resp->headers=presp->headers;
    time_t backend_time_delta=presp->date? presp->date-nxe_get_current_http_time(loop) : 0;
    nxd_http_proxy_pool_report_backend_time_delta(hpx->pool, backend_time_delta);
    backend_time_delta=nxd_http_proxy_pool_get_backend_time_delta(hpx->pool);
    resp->date=presp->date? presp->date-backend_time_delta : 0;
    resp->last_modified=presp->last_modified? presp->last_modified-backend_time_delta : 0;
    resp->expires=presp->expires? presp->expires-backend_time_delta : 0;
    resp->cache_control=presp->cache_control;
    resp->max_age=presp->max_age;
    resp->no_cache=presp->no_cache;
    resp->cache_private=presp->cache_private;
    resp->content_out=&rdata->rb_resp.data_out;
    nxweb_start_sending_response(conn, resp);
    rdata->response_sending_started=1;
    nxweb_server_config.access_log_on_proxy_response(&conn->hsp.req, hpx, presp);
    //nxweb_log_error("proxy request [%d] start sending response", conn->hpx->hcp.request_count);
  }
  else if (data.i==NXD_HCP_REQUEST_COMPLETE) {
    rdata->proxy_request_complete=1;
    //nxweb_log_error("proxy request [%d] complete", conn->hpx->hcp.request_count);
  }
  else if (data.i<0) {
    rdata->proxy_request_error=1;
    if (/*rdata->hpx->hcp.request_complete ||*/ rdata->proxy_request_complete) {
      nxweb_log_warning("proxy request conn=%p rc=%d retry=%d error=%d; error after request_complete; ignored", conn, rdata->hpx->hcp.request_count, rdata->retry_count, data.i);
      // ignore errors after request_complete; keep connection running
    }
    else if (rdata->response_sending_started) {
      nxweb_log_error("proxy request conn=%p rc=%d retry=%d error=%d; error while response_sending_started but backend request not complete; request failed",
                      conn, rdata->hpx->hcp.request_count, rdata->retry_count, data.i);
      // ignore errors after response_sending_started; keep connection running
      fail_proxy_request(rdata);
    }
    else {
      nxe_unset_timer(loop, NXWEB_TIMER_BACKEND, &rdata->timer_backend);
      if (rdata->retry_count>=NXWEB_PROXY_RETRY_COUNT || rdata->hpx->hcp.req_body_sending_started /*|| rdata->response_sending_started*/) {
        nxweb_log_error("proxy request conn=%p rc=%d retry=%d error=%d; failed", conn, rdata->hpx->hcp.request_count, rdata->retry_count, data.i);
        fail_proxy_request(rdata);
      }
      else {
        if (rdata->retry_count || !(data.i==NXE_ERROR || data.i==NXE_HUP || data.i==NXE_RDHUP || data.i==NXE_RDCLOSED)) {
          nxweb_log_warning("proxy request conn=%p rc=%d retry=%d error=%d; retrying", conn, rdata->hpx->hcp.request_count, rdata->retry_count, data.i);
        }
        retry_proxy_request(rdata);
      }
    }
  }
}