LWS_VISIBLE int lws_http_client_read(struct lws *wsi, char **buf, int *len) { int rlen, n; rlen = lws_ssl_capable_read(wsi, (unsigned char *)*buf, *len); if (rlen < 0) return -1; *len = rlen; if (rlen == 0) return 0; // lwsl_err("%s: read %d\n", __func__, rlen); /* allow the source to signal he has data again next time */ wsi->client_rx_avail = 0; lws_change_pollfd(wsi, 0, LWS_POLLIN); /* * server may insist on transfer-encoding: chunked, * so http client must deal with it */ spin_chunks: while (wsi->chunked && (wsi->chunk_parser != ELCP_CONTENT) && *len) { switch (wsi->chunk_parser) { case ELCP_HEX: if ((*buf)[0] == '\x0d') { wsi->chunk_parser = ELCP_CR; break; } n = char_to_hex((*buf)[0]); if (n < 0) return -1; wsi->chunk_remaining <<= 4; wsi->chunk_remaining |= n; break; case ELCP_CR: if ((*buf)[0] != '\x0a') return -1; wsi->chunk_parser = ELCP_CONTENT; lwsl_info("chunk %d\n", wsi->chunk_remaining); if (wsi->chunk_remaining) break; lwsl_info("final chunk\n"); goto completed; case ELCP_CONTENT: break; case ELCP_POST_CR: if ((*buf)[0] != '\x0d') return -1; wsi->chunk_parser = ELCP_POST_LF; break; case ELCP_POST_LF: if ((*buf)[0] != '\x0a') return -1; wsi->chunk_parser = ELCP_HEX; wsi->chunk_remaining = 0; break; } (*buf)++; (*len)--; } if (wsi->chunked && !wsi->chunk_remaining) return 0; if (wsi->u.http.content_remain && (int)wsi->u.http.content_remain < *len) n = wsi->u.http.content_remain; else n = *len; if (wsi->chunked && wsi->chunk_remaining && wsi->chunk_remaining < n) n = wsi->chunk_remaining; #ifdef LWS_WITH_HTTP_PROXY /* hubbub */ if (wsi->perform_rewrite) lws_rewrite_parse(wsi->rw, (unsigned char *)*buf, n); else #endif if (user_callback_handle_rxflow(wsi->protocol->callback, wsi, LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ, wsi->user_space, *buf, n)) return -1; if (wsi->chunked && wsi->chunk_remaining) { (*buf) += n; wsi->chunk_remaining -= n; *len -= n; } if (wsi->chunked && !wsi->chunk_remaining) wsi->chunk_parser = ELCP_POST_CR; if (wsi->chunked && *len) { goto spin_chunks; } if (wsi->chunked) return 0; wsi->u.http.content_remain -= n; if (wsi->u.http.content_remain || !wsi->u.http.content_length) return 0; completed: if (user_callback_handle_rxflow(wsi->protocol->callback, wsi, LWS_CALLBACK_COMPLETED_CLIENT_HTTP, wsi->user_space, NULL, 0)) return -1; if (lws_http_transaction_completed_client(wsi)) return -1; return 0; }
LWS_VISIBLE int lws_http_client_read(struct lws *wsi, char **buf, int *len) { int rlen, n; rlen = lws_ssl_capable_read(wsi, (unsigned char *)*buf, *len); *len = 0; // lwsl_notice("%s: rlen %d\n", __func__, rlen); /* allow the source to signal he has data again next time */ lws_change_pollfd(wsi, 0, LWS_POLLIN); if (rlen == LWS_SSL_CAPABLE_ERROR) { lwsl_notice("%s: SSL capable error\n", __func__); return -1; } if (rlen == 0) return -1; if (rlen < 0) return 0; *len = rlen; wsi->client_rx_avail = 0; /* * server may insist on transfer-encoding: chunked, * so http client must deal with it */ spin_chunks: while (wsi->chunked && (wsi->chunk_parser != ELCP_CONTENT) && *len) { switch (wsi->chunk_parser) { case ELCP_HEX: if ((*buf)[0] == '\x0d') { wsi->chunk_parser = ELCP_CR; break; } n = char_to_hex((*buf)[0]); if (n < 0) { lwsl_debug("chunking failure\n"); return -1; } wsi->chunk_remaining <<= 4; wsi->chunk_remaining |= n; break; case ELCP_CR: if ((*buf)[0] != '\x0a') { lwsl_debug("chunking failure\n"); return -1; } wsi->chunk_parser = ELCP_CONTENT; lwsl_info("chunk %d\n", wsi->chunk_remaining); if (wsi->chunk_remaining) break; lwsl_info("final chunk\n"); goto completed; case ELCP_CONTENT: break; case ELCP_POST_CR: if ((*buf)[0] != '\x0d') { lwsl_debug("chunking failure\n"); return -1; } wsi->chunk_parser = ELCP_POST_LF; break; case ELCP_POST_LF: if ((*buf)[0] != '\x0a') return -1; wsi->chunk_parser = ELCP_HEX; wsi->chunk_remaining = 0; break; } (*buf)++; (*len)--; } if (wsi->chunked && !wsi->chunk_remaining) return 0; if (wsi->http.rx_content_remain && wsi->http.rx_content_remain < (unsigned int)*len) n = (int)wsi->http.rx_content_remain; else n = *len; if (wsi->chunked && wsi->chunk_remaining && wsi->chunk_remaining < n) n = wsi->chunk_remaining; #ifdef LWS_WITH_HTTP_PROXY /* hubbub */ if (wsi->http.perform_rewrite) lws_rewrite_parse(wsi->http.rw, (unsigned char *)*buf, n); else #endif { struct lws *wsi_eff = lws_client_wsi_effective(wsi); if (user_callback_handle_rxflow(wsi_eff->protocol->callback, wsi_eff, LWS_CALLBACK_RECEIVE_CLIENT_HTTP_READ, wsi_eff->user_space, *buf, n)) { lwsl_debug("%s: RECEIVE_CLIENT_HTTP_READ returned -1\n", __func__); return -1; } } if (wsi->chunked && wsi->chunk_remaining) { (*buf) += n; wsi->chunk_remaining -= n; *len -= n; } if (wsi->chunked && !wsi->chunk_remaining) wsi->chunk_parser = ELCP_POST_CR; if (wsi->chunked && *len) goto spin_chunks; if (wsi->chunked) return 0; /* if we know the content length, decrement the content remaining */ if (wsi->http.rx_content_length > 0) wsi->http.rx_content_remain -= n; // lwsl_notice("rx_content_remain %lld, rx_content_length %lld\n", // wsi->http.rx_content_remain, wsi->http.rx_content_length); if (wsi->http.rx_content_remain || !wsi->http.rx_content_length) return 0; completed: if (lws_http_transaction_completed_client(wsi)) { lwsl_notice("%s: transaction completed says -1\n", __func__); return -1; } return 0; }