+static int
+state_cln_wait_method (http_conn_t *hc, transport_send_params_t *sp)
+{
+ session_t *as;
+ http_msg_t msg;
+ app_worker_t *app_wrk;
+ int rv, content_length;
+
+ rv = read_http_message (hc);
+ if (rv)
+ return HTTP_SM_STOP;
+
+ msg.type = HTTP_MSG_REPLY;
+ msg.content_type = HTTP_CONTENT_TEXT_HTML;
+ msg.code = HTTP_STATUS_OK;
+ msg.data.type = HTTP_MSG_DATA_INLINE;
+ msg.data.len = 0;
+
+ rv = parse_http_header (hc, &content_length);
+ if (rv)
+ {
+ clib_warning ("failed to parse http reply");
+ session_transport_closing_notify (&hc->connection);
+ http_disconnect_transport (hc);
+ return -1;
+ }
+
+ msg.data.len = content_length;
+ u32 dlen = vec_len (hc->rx_buf) - hc->rx_buf_offset;
+ as = session_get_from_handle (hc->h_pa_session_handle);
+ svm_fifo_seg_t segs[2] = { { (u8 *) &msg, sizeof (msg) },
+ { &hc->rx_buf[hc->rx_buf_offset], dlen } };
+
+ rv = svm_fifo_enqueue_segments (as->rx_fifo, segs, 2, 0 /* allow partial */);
+ if (rv < 0)
+ {
+ clib_warning ("error enqueue");
+ return HTTP_SM_ERROR;
+ }
+ hc->rx_buf_offset += dlen;
+ hc->http_state = HTTP_STATE_IO_MORE_DATA;
+ hc->to_recv = content_length - dlen;
+
+ if (hc->rx_buf_offset == vec_len (hc->rx_buf))
+ {
+ vec_reset_length (hc->rx_buf);
+ hc->rx_buf_offset = 0;
+ }
+
+ if (hc->to_recv == 0)
+ {
+ hc->rx_buf_offset = 0;
+ vec_reset_length (hc->rx_buf);
+ hc->http_state = HTTP_STATE_WAIT_APP;
+ }
+
+ app_wrk = app_worker_get_if_valid (as->app_wrk_index);
+ app_worker_lock_and_send_event (app_wrk, as, SESSION_IO_EVT_RX);
+ return HTTP_SM_STOP;
+}
+
+static int
+cln_drain_rx_buf (http_conn_t *hc, session_t *ts, session_t *as)
+{
+ app_worker_t *app_wrk;
+ u32 max_enq, n_enq, dlen = vec_len (hc->rx_buf) - hc->rx_buf_offset;
+ int rv;
+
+ max_enq = svm_fifo_max_enqueue (as->rx_fifo);
+ n_enq = clib_min (max_enq, dlen);
+ rv = svm_fifo_enqueue (as->rx_fifo, n_enq, &hc->rx_buf[hc->rx_buf_offset]);
+ if (rv < 0)
+ {
+ clib_warning ("enqueue failed");
+ return -1;
+ }
+
+ hc->rx_buf_offset += rv;
+
+ if (hc->rx_buf_offset >= vec_len (hc->rx_buf))
+ {
+ vec_reset_length (hc->rx_buf);
+ hc->rx_buf_offset = 0;
+ }
+
+ app_wrk = app_worker_get_if_valid (as->app_wrk_index);
+ ASSERT (app_wrk);
+
+ app_worker_lock_and_send_event (app_wrk, as, SESSION_IO_EVT_RX);
+ return 1;
+}
+
+static http_sm_result_t
+state_cln_recv_more_data (http_conn_t *hc, transport_send_params_t *sp)
+{
+ session_t *as;
+ u32 max_deq;
+ session_t *ts;
+ int n_read, rv;
+
+ as = session_get_from_handle (hc->h_pa_session_handle);
+ ts = session_get_from_handle (hc->h_tc_session_handle);
+
+ u32 dlen = vec_len (hc->rx_buf) - hc->rx_buf_offset;
+ if (dlen)
+ {
+ rv = cln_drain_rx_buf (hc, ts, as);
+ if (rv < 0)
+ {
+ clib_warning ("drain rx error!");
+ return HTTP_SM_ERROR;
+ }
+ goto maybe_reschedule;
+ }
+
+ if (hc->to_recv == 0)
+ {
+ ASSERT (vec_len (hc->rx_buf) == 0);
+ ASSERT (hc->rx_buf_offset == 0);
+ hc->http_state = HTTP_STATE_WAIT_APP;
+ return HTTP_SM_STOP;
+ }
+
+ max_deq = svm_fifo_max_dequeue (ts->rx_fifo);
+ if (max_deq == 0)
+ return HTTP_SM_STOP;
+
+ ASSERT (vec_len (hc->rx_buf) == 0);
+ ASSERT (hc->rx_buf_offset == 0);
+
+ vec_validate (hc->rx_buf, max_deq - 1);
+ n_read = svm_fifo_dequeue (ts->rx_fifo, max_deq, hc->rx_buf);
+ ASSERT (n_read == max_deq);
+
+ if (svm_fifo_is_empty (ts->rx_fifo))
+ svm_fifo_unset_event (ts->rx_fifo);
+
+ hc->to_recv -= n_read;
+ vec_set_len (hc->rx_buf, max_deq);
+
+maybe_reschedule:
+ if (hc->rx_buf_offset < vec_len (hc->rx_buf) ||
+ svm_fifo_max_dequeue_cons (ts->rx_fifo))
+ {
+ if (svm_fifo_set_event (ts->rx_fifo))
+ session_send_io_evt_to_thread (ts->rx_fifo, SESSION_IO_EVT_BUILTIN_RX);
+ }
+ return HTTP_SM_CONTINUE;
+}
+
+static http_sm_result_t
+state_cln_wait_app (http_conn_t *hc, transport_send_params_t *sp)
+{
+ session_t *as;
+ http_msg_t msg;
+ http_status_code_t ec;
+ u8 *buf = 0, *request;
+ u32 offset;
+ int rv;
+
+ as = session_get_from_handle (hc->h_pa_session_handle);
+ rv = svm_fifo_dequeue (as->tx_fifo, sizeof (msg), (u8 *) &msg);
+ ASSERT (rv == sizeof (msg));
+ if (msg.type != HTTP_MSG_REQUEST || msg.data.type > HTTP_MSG_DATA_PTR)
+ {
+ clib_warning ("unexpected msg type from app %u", msg.type);
+ ec = HTTP_STATUS_INTERNAL_ERROR;
+ goto error;
+ }
+
+ vec_validate (buf, msg.data.len - 1);
+ rv = svm_fifo_dequeue (as->tx_fifo, msg.data.len, buf);
+ ASSERT (rv == msg.data.len);