* into multiple fragments. They may contain unknown headers with arbitrary
* argument lengths. So, we parse using a single-character at a time state
* machine that is completely independent of packet size.
+ *
+ * Returns <0 for error or length of chars consumed from buf (up to len)
*/
LWS_VISIBLE int
-lws_read(struct lws_context *context, struct lws *wsi, unsigned char *buf,
- size_t len)
+lws_read(struct lws *wsi, unsigned char *buf, lws_filepos_t len)
{
- unsigned char *last_char;
- int body_chunk_len;
+ unsigned char *last_char, *oldbuf = buf;
+ lws_filepos_t body_chunk_len;
size_t n;
+ lwsl_debug("%s: incoming len %d state %d\n", __func__, (int)len, wsi->state);
+
switch (wsi->state) {
#ifdef LWS_USE_HTTP2
- case WSI_STATE_HTTP2_AWAIT_CLIENT_PREFACE:
- case WSI_STATE_HTTP2_ESTABLISHED_PRE_SETTINGS:
- case WSI_STATE_HTTP2_ESTABLISHED:
+ case LWSS_HTTP2_AWAIT_CLIENT_PREFACE:
+ case LWSS_HTTP2_ESTABLISHED_PRE_SETTINGS:
+ case LWSS_HTTP2_ESTABLISHED:
n = 0;
while (n < len) {
/*
/* account for what we're using in rxflow buffer */
if (wsi->rxflow_buffer)
wsi->rxflow_pos++;
- if (lws_http2_parser(context, wsi, buf[n++]))
+ if (lws_http2_parser(wsi, buf[n++])) {
+ lwsl_debug("%s: http2_parser bailed\n", __func__);
goto bail;
+ }
}
break;
#endif
-http_new:
- case WSI_STATE_HTTP:
+
+ case LWSS_HTTP_ISSUING_FILE:
+ return 0;
+
+ case LWSS_CLIENT_HTTP_ESTABLISHED:
+ break;
+
+ case LWSS_HTTP:
wsi->hdr_parsing_completed = 0;
/* fallthru */
- case WSI_STATE_HTTP_ISSUING_FILE:
- wsi->state = WSI_STATE_HTTP_HEADERS;
- wsi->u.hdr.parser_state = WSI_TOKEN_NAME_PART;
- wsi->u.hdr.lextable_pos = 0;
- /* fallthru */
- case WSI_STATE_HTTP_HEADERS:
+
+ case LWSS_HTTP_HEADERS:
+ if (!wsi->u.hdr.ah) {
+ lwsl_err("%s: LWSS_HTTP_HEADERS: NULL ah\n", __func__);
+ assert(0);
+ }
lwsl_parser("issuing %d bytes to parser\n", (int)len);
- if (lws_handshake_client(wsi, &buf, len))
+ if (lws_handshake_client(wsi, &buf, (size_t)len))
goto bail;
last_char = buf;
- if (lws_handshake_server(context, wsi, &buf, len))
+ if (lws_handshake_server(wsi, &buf, (size_t)len))
/* Handshake indicates this session is done. */
goto bail;
- /* It's possible that we've exhausted our data already, but
- * lws_handshake_server doesn't update len for us. Figure out how
- * much was read, so that we can proceed appropriately: */
+ /* we might have transitioned to RAW */
+ if (wsi->mode == LWSCM_RAW)
+ /* we gave the read buffer to RAW handler already */
+ goto read_ok;
+
+ /*
+ * It's possible that we've exhausted our data already, or
+ * rx flow control has stopped us dealing with this early,
+ * but lws_handshake_server doesn't update len for us.
+ * Figure out how much was read, so that we can proceed
+ * appropriately:
+ */
len -= (buf - last_char);
+ lwsl_debug("%s: thinks we have used %ld\n", __func__, (long)len);
if (!wsi->hdr_parsing_completed)
/* More header content on the way */
goto read_ok;
switch (wsi->state) {
- case WSI_STATE_HTTP:
- case WSI_STATE_HTTP_HEADERS:
- goto http_complete;
- case WSI_STATE_HTTP_ISSUING_FILE:
+ case LWSS_HTTP:
+ case LWSS_HTTP_HEADERS:
+ goto read_ok;
+ case LWSS_HTTP_ISSUING_FILE:
goto read_ok;
- case WSI_STATE_HTTP_BODY:
+ case LWSS_HTTP_BODY:
wsi->u.http.content_remain =
wsi->u.http.content_length;
if (wsi->u.http.content_remain)
}
break;
- case WSI_STATE_HTTP_BODY:
+ case LWSS_HTTP_BODY:
http_postbody:
while (len && wsi->u.http.content_remain) {
/* Copy as much as possible, up to the limit of:
body_chunk_len = min(wsi->u.http.content_remain,len);
wsi->u.http.content_remain -= body_chunk_len;
len -= body_chunk_len;
+#ifdef LWS_WITH_CGI
+ if (wsi->cgi) {
+ struct lws_cgi_args args;
- n = wsi->protocol->callback(
- lws_get_ctx(wsi), wsi,
- LWS_CALLBACK_HTTP_BODY, wsi->user_space,
- buf, body_chunk_len);
- if (n)
- goto bail;
+ args.ch = LWS_STDIN;
+ args.stdwsi = &wsi->cgi->stdwsi[0];
+ args.data = buf;
+ args.len = body_chunk_len;
- buf += body_chunk_len;
+ /* returns how much used */
+ n = user_callback_handle_rxflow(
+ wsi->protocol->callback,
+ wsi, LWS_CALLBACK_CGI_STDIN_DATA,
+ wsi->user_space,
+ (void *)&args, 0);
+ if ((int)n < 0)
+ goto bail;
+ } else {
+#endif
+ n = wsi->protocol->callback(wsi,
+ LWS_CALLBACK_HTTP_BODY, wsi->user_space,
+ buf, (size_t)body_chunk_len);
+ if (n)
+ goto bail;
+ n = (size_t)body_chunk_len;
+#ifdef LWS_WITH_CGI
+ }
+#endif
+ buf += n;
if (wsi->u.http.content_remain) {
lws_set_timeout(wsi, PENDING_TIMEOUT_HTTP_CONTENT,
- AWAITING_TIMEOUT);
+ wsi->context->timeout_secs);
break;
}
/* he sent all the content in time */
postbody_completion:
+#ifdef LWS_WITH_CGI
+ /* if we're running a cgi, we can't let him off the hook just because he sent his POST data */
+ if (wsi->cgi)
+ lws_set_timeout(wsi, PENDING_TIMEOUT_CGI, wsi->context->timeout_secs);
+ else
+#endif
lws_set_timeout(wsi, NO_PENDING_TIMEOUT, 0);
- n = wsi->protocol->callback(
- lws_get_ctx(wsi), wsi,
- LWS_CALLBACK_HTTP_BODY_COMPLETION,
- wsi->user_space, NULL, 0);
- if (n)
- goto bail;
+#ifdef LWS_WITH_CGI
+ if (!wsi->cgi)
+#endif
+ {
+ n = wsi->protocol->callback(wsi,
+ LWS_CALLBACK_HTTP_BODY_COMPLETION,
+ wsi->user_space, NULL, 0);
+ if (n)
+ goto bail;
+ }
- goto http_complete;
+ break;
}
break;
- case WSI_STATE_ESTABLISHED:
- case WSI_STATE_AWAITING_CLOSE_ACK:
- if (lws_handshake_client(wsi, &buf, len))
+ case LWSS_ESTABLISHED:
+ case LWSS_AWAITING_CLOSE_ACK:
+ case LWSS_WAITING_TO_SEND_CLOSE_NOTIFICATION:
+ case LWSS_SHUTDOWN:
+ if (lws_handshake_client(wsi, &buf, (size_t)len))
goto bail;
switch (wsi->mode) {
- case LWS_CONNMODE_WS_SERVING:
+ case LWSCM_WS_SERVING:
- if (lws_interpret_incoming_packet(wsi, buf, len) < 0) {
+ if (lws_interpret_incoming_packet(wsi, &buf, (size_t)len) < 0) {
lwsl_info("interpret_incoming_packet has bailed\n");
goto bail;
}
}
break;
default:
- lwsl_err("lws_read: Unhandled state\n");
+ lwsl_err("%s: Unhandled state %d\n", __func__, wsi->state);
break;
}
read_ok:
/* Nothing more to do for now */
- lwsl_debug("lws_read: read_ok\n");
-
- return 0;
-
-http_complete:
- lwsl_debug("lws_read: http_complete\n");
-
-#ifndef LWS_NO_SERVER
- /* Did the client want to keep the HTTP connection going? */
- if (lws_http_transaction_completed(wsi))
- goto bail;
-#endif
- /* If we have more data, loop back around: */
- if (len)
- goto http_new;
+ lwsl_info("%s: read_ok, used %ld\n", __func__, (long)(buf - oldbuf));
- return 0;
+ return buf - oldbuf;
bail:
- lwsl_debug("closing connection at lws_read bail:\n");
+ //lwsl_notice("closing connection at lws_read bail:\n");
lws_close_free_wsi(wsi, LWS_CLOSE_STATUS_NOSTATUS);
return -1;