1181 lines
43 KiB
C
1181 lines
43 KiB
C
/*
|
|
*********************************************************************************************************
|
|
* uC/HTTP
|
|
* Hypertext Transfer Protocol
|
|
*
|
|
* Copyright 2004-2020 Silicon Laboratories Inc. www.silabs.com
|
|
*
|
|
* SPDX-License-Identifier: APACHE-2.0
|
|
*
|
|
* This software is subject to an open source license and is distributed by
|
|
* Silicon Laboratories Inc. pursuant to the terms of the Apache License,
|
|
* Version 2.0 available at www.apache.org/licenses/LICENSE-2.0.
|
|
*
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*
|
|
* HTTP CLIENT RESPONSE MODULE
|
|
*
|
|
* Filename : http-c_resp.c
|
|
* Version : V3.01.00
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
* INCLUDE FILES
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
*/
|
|
#define MICRIUM_SOURCE
|
|
#define HTTPc_RESP_MODULE
|
|
|
|
#include <net_ascii.h>
|
|
#include <net_util.h>
|
|
|
|
#include "http-c_resp.h"
|
|
#include "http-c_conn.h"
|
|
#include "http-c_sock.h"
|
|
#ifdef HTTPc_WEBSOCK_MODULE_EN
|
|
#include "http-c_websock.h"
|
|
#endif
|
|
|
|
/**********************************************/
|
|
#include "http_cli.h"
|
|
/**********************************************/
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
* LOCAL FUNCTION PROTOTYPES
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void HTTPcResp_ParseStatusLine(HTTPc_CONN *p_conn,
|
|
HTTPc_ERR *p_err);
|
|
|
|
static HTTP_PROTOCOL_VER HTTPcResp_ParseProtocolVer(const CPU_CHAR *p_resp_line,
|
|
CPU_INT32U str_len);
|
|
|
|
static HTTP_STATUS_CODE HTTPcResp_ParseStatusCode(const CPU_CHAR *p_resp_line,
|
|
CPU_INT32U str_len);
|
|
|
|
static const CPU_CHAR *HTTPcResp_ParseReasonPhrase(const CPU_CHAR *p_resp_line,
|
|
CPU_INT32U str_len,
|
|
HTTP_STATUS_CODE status_code);
|
|
|
|
static void HTTPcResp_ParseHdr(HTTPc_CONN *p_conn,
|
|
HTTPc_ERR *p_err);
|
|
|
|
static void HTTPcResp_Body(HTTPc_CONN *p_conn,
|
|
HTTPc_ERR *p_err);
|
|
|
|
static void HTTPcResp_BodyStd(HTTPc_CONN *p_conn,
|
|
HTTPc_ERR *p_err);
|
|
|
|
static void HTTPcResp_BodyChunk(HTTPc_CONN *p_conn,
|
|
HTTPc_ERR *p_err);
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* HTTPcResp()
|
|
*
|
|
* Description : Main HTTP response processing function.
|
|
*
|
|
* Argument(s) : p_conn Pointer to current HTTPc Connection.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* HTTPc_ERR_NONE Response processing operation successful.
|
|
* HTTPc_ERR_TRANS_RX_MORE_DATA_REQUIRED More data required to continue processing.
|
|
* HTTPc_ERR_CONN_INVALID_STATE Invalid Connection state.
|
|
*
|
|
* ------------ RETURNED BY HTTPcSock_ConnDataRx() ------------
|
|
* See HTTPcSock_ConnDataRx() for additional return error codes.
|
|
*
|
|
* ------------ RETURNED BY HTTPcResp_ParseStatusLine() ------------
|
|
* See HTTPcResp_ParseStatusLine() for additional return error codes.
|
|
*
|
|
* ------------ RETURNED BY HTTPcResp_ParseHdr() ------------
|
|
* See HTTPcResp_ParseHdr() for additional return error codes.
|
|
*
|
|
* ------------ RETURNED BY HTTPcResp_Body() ------------
|
|
* See HTTPcResp_Body() for additional return error codes
|
|
*
|
|
* Return(s) : DEF_YES, if response processing is complete successfully.
|
|
* DEF_NO, otherwise.
|
|
*
|
|
* Caller(s) : HTTPcTask_Handler().
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*修改,接收处理接口*/
|
|
CPU_BOOLEAN HTTPcResp(HTTPc_CONN *p_conn,
|
|
HTTPc_ERR *p_err)
|
|
{
|
|
CPU_BOOLEAN rx_data;
|
|
CPU_BOOLEAN process;
|
|
CPU_BOOLEAN sock_rdy_rd;
|
|
CPU_BOOLEAN sock_rdy_err;
|
|
CPU_BOOLEAN done;
|
|
|
|
|
|
done = DEF_NO;
|
|
process = DEF_NO;
|
|
rx_data = DEF_BIT_IS_SET(p_conn->RespFlags, HTTPc_FLAG_RESP_RX_MORE_DATA);
|
|
|
|
if (rx_data == DEF_YES) {
|
|
|
|
sock_rdy_rd = DEF_BIT_IS_SET(p_conn->SockFlags, HTTPc_FLAG_SOCK_RDY_RD);
|
|
sock_rdy_err = DEF_BIT_IS_SET(p_conn->SockFlags, HTTPc_FLAG_SOCK_RDY_ERR);
|
|
|
|
/* if((sock_rdy_rd == DEF_YES) || */
|
|
/* (sock_rdy_err == DEF_YES)) { */
|
|
process = HTTPcSock_ConnDataRx(p_conn, DEF_NULL, p_err);
|
|
switch (*p_err) {
|
|
case HTTPc_ERR_NONE:
|
|
case HTTPc_ERR_CONN_SOCK_RX:
|
|
break;
|
|
|
|
|
|
default:
|
|
goto exit;
|
|
}
|
|
/* } */
|
|
}
|
|
|
|
switch (p_conn->State) {
|
|
case HTTPc_CONN_STATE_RESP_INIT:
|
|
DEF_BIT_SET(p_conn->RespFlags, HTTPc_FLAG_RESP_RX_MORE_DATA);
|
|
if (process == DEF_YES) {
|
|
DEF_BIT_CLR(p_conn->RespFlags, HTTPc_FLAG_RESP_RX_MORE_DATA);
|
|
p_conn->State = HTTPc_CONN_STATE_RESP_STATUS_LINE;
|
|
}
|
|
*p_err = HTTPc_ERR_NONE;
|
|
break;
|
|
|
|
|
|
case HTTPc_CONN_STATE_RESP_STATUS_LINE:
|
|
HTTPcResp_ParseStatusLine(p_conn, p_err);
|
|
switch (*p_err) {
|
|
case HTTPc_ERR_NONE:
|
|
DEF_BIT_CLR(p_conn->RespFlags, HTTPc_FLAG_RESP_RX_MORE_DATA);
|
|
p_conn->State = HTTPc_CONN_STATE_RESP_HDR;
|
|
break;
|
|
|
|
|
|
case HTTPc_ERR_TRANS_RX_MORE_DATA_REQUIRED:
|
|
DEF_BIT_SET(p_conn->RespFlags, HTTPc_FLAG_RESP_RX_MORE_DATA);
|
|
break;
|
|
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
|
|
case HTTPc_CONN_STATE_RESP_HDR:
|
|
HTTPcResp_ParseHdr(p_conn, p_err);
|
|
switch (*p_err) {
|
|
case HTTPc_ERR_NONE:
|
|
DEF_BIT_CLR(p_conn->RespFlags, HTTPc_FLAG_RESP_RX_MORE_DATA);
|
|
p_conn->State = HTTPc_CONN_STATE_RESP_BODY;
|
|
break;
|
|
|
|
|
|
case HTTPc_ERR_TRANS_RX_MORE_DATA_REQUIRED:
|
|
DEF_BIT_SET(p_conn->RespFlags, HTTPc_FLAG_RESP_RX_MORE_DATA);
|
|
break;
|
|
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
|
|
case HTTPc_CONN_STATE_RESP_BODY:
|
|
case HTTPc_CONN_STATE_RESP_BODY_CHUNK_SIZE:
|
|
case HTTPc_CONN_STATE_RESP_BODY_CHUNK_DATA:
|
|
case HTTPc_CONN_STATE_RESP_BODY_CHUNK_CRLF:
|
|
case HTTPc_CONN_STATE_RESP_BODY_CHUNK_LAST:
|
|
HTTPcResp_Body(p_conn, p_err);
|
|
switch (*p_err) {
|
|
case HTTPc_ERR_NONE:
|
|
DEF_BIT_CLR(p_conn->RespFlags, HTTPc_FLAG_RESP_RX_MORE_DATA);
|
|
p_conn->State = HTTPc_CONN_STATE_RESP_COMPLETED;
|
|
break;
|
|
|
|
|
|
case HTTPc_ERR_TRANS_RX_MORE_DATA_REQUIRED:
|
|
DEF_BIT_SET(p_conn->RespFlags, HTTPc_FLAG_RESP_RX_MORE_DATA);
|
|
break;
|
|
|
|
|
|
default:
|
|
break;
|
|
}
|
|
break;
|
|
|
|
|
|
case HTTPc_CONN_STATE_RESP_COMPLETED:
|
|
done = DEF_YES;
|
|
p_conn->State = HTTPc_CONN_STATE_COMPLETED;
|
|
*p_err = HTTPc_ERR_NONE;
|
|
break;
|
|
|
|
|
|
default:
|
|
*p_err = HTTPc_ERR_CONN_INVALID_STATE;
|
|
break;
|
|
}
|
|
|
|
|
|
exit:
|
|
return (done);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
* LOCAL FUNCTIONS
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* HTTPcResp_ParseStatusLine()
|
|
*
|
|
* Description : (1) HTTP Response status line processing :
|
|
* (a) Parse HTTP protocol version received.
|
|
* (b) Parse Status Code received.
|
|
* (c) Parse Reason phrase received.
|
|
*
|
|
*
|
|
* Argument(s) : p_conn Pointer to current HTTPc Connection.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* HTTPc_ERR_NONE Status Line successfully parsed.
|
|
* HTTPc_ERR_TRANS_RX_MORE_DATA_REQUIRED
|
|
* HTTPc_ERR_RESP_INVALID_FORMAT
|
|
* HTTPc_ERR_RESP_INVALID_PROTOCOL_VER
|
|
* HTTPc_ERR_RESP_INVALID_STATUS_CODE
|
|
* HTTPc_ERR_RESP_INVALID_REASON_PHRASE
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Caller(s) : HTTPcResp().
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void HTTPcResp_ParseStatusLine(HTTPc_CONN *p_conn,
|
|
HTTPc_ERR *p_err)
|
|
{
|
|
HTTPc_REQ *p_req;
|
|
HTTPc_RESP *p_resp;
|
|
CPU_CHAR *p_resp_line_start;
|
|
CPU_CHAR *p_resp_line_end;
|
|
CPU_SIZE_T len;
|
|
|
|
|
|
p_req = p_conn->ReqListHeadPtr;
|
|
p_resp = p_req->RespPtr;
|
|
|
|
/* Clean response object. */
|
|
p_resp->ContentLen = 0;
|
|
p_resp->ContentType = HTTP_CONTENT_TYPE_NONE;
|
|
p_resp->ProtocolVer = HTTP_PROTOCOL_VER_UNKNOWN;
|
|
p_resp->ReasonPhrasePtr = DEF_NULL;
|
|
p_resp->StatusCode = HTTP_STATUS_UNKNOWN;
|
|
|
|
len = p_conn->RxDataLenRem;
|
|
if (len <= sizeof(HTTP_STR_METHOD_GET)) {
|
|
*p_err = HTTPc_ERR_TRANS_RX_MORE_DATA_REQUIRED;
|
|
return;
|
|
}
|
|
|
|
/* ------------ RETRIEVE RESP STATUS LINE ------------- */
|
|
/* Search beginning and remove white spaces before Resp.*/
|
|
p_resp_line_start = HTTP_StrGraphSrchFirst(p_conn->RxBufPtr, len);
|
|
if (p_resp_line_start == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_TRANS_RX_MORE_DATA_REQUIRED;
|
|
return;
|
|
}
|
|
|
|
/* Find end of resp status line. */
|
|
len -= (p_resp_line_start - p_conn->BufPtr);
|
|
p_resp_line_end = Str_Str_N(p_resp_line_start, STR_CR_LF, len);
|
|
if (p_resp_line_end == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_RESP_FORMAT_INVALID;
|
|
return;
|
|
}
|
|
|
|
len = p_resp_line_end - p_resp_line_start;
|
|
/* ---------- PARSE RESPONSE PROTOCOL VERSION --------- */
|
|
p_resp->ProtocolVer = HTTPcResp_ParseProtocolVer(p_resp_line_start, len);
|
|
switch (p_resp->ProtocolVer) {
|
|
case HTTP_PROTOCOL_VER_1_1:
|
|
break;
|
|
|
|
|
|
case HTTP_PROTOCOL_VER_1_0:
|
|
case HTTP_PROTOCOL_VER_0_9:
|
|
case HTTP_PROTOCOL_VER_UNKNOWN:
|
|
default:
|
|
*p_err = HTTPc_ERR_RESP_PROTOCOL_VER_INVALID;
|
|
return;
|
|
}
|
|
|
|
/* ------------ FIND SPACE IN STATUS LINE ------------- */
|
|
p_resp_line_start = Str_Char_N(p_resp_line_start, len, ASCII_CHAR_SPACE);
|
|
if (p_resp_line_start == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_RESP_FORMAT_INVALID;
|
|
return;
|
|
}
|
|
p_resp_line_start++;
|
|
len = p_resp_line_end - p_resp_line_start;
|
|
/* ------------ PARSE RESPONSE STATUS CODE ------------ */
|
|
p_resp->StatusCode = HTTPcResp_ParseStatusCode(p_resp_line_start, len);
|
|
switch (p_resp->StatusCode) {
|
|
case HTTP_STATUS_CONTINUE:
|
|
case HTTP_STATUS_SWITCHING_PROTOCOLS:
|
|
case HTTP_STATUS_PROCESSING:
|
|
case HTTP_STATUS_EARLY_HINTS:
|
|
case HTTP_STATUS_OK:
|
|
case HTTP_STATUS_CREATED:
|
|
case HTTP_STATUS_ACCEPTED:
|
|
case HTTP_STATUS_NON_AUTHORITATIVE_INFORMATION:
|
|
case HTTP_STATUS_NO_CONTENT:
|
|
case HTTP_STATUS_RESET_CONTENT:
|
|
case HTTP_STATUS_PARTIAL_CONTENT:
|
|
case HTTP_STATUS_MULTI_STATUS:
|
|
case HTTP_STATUS_ALREADY_REPORTED:
|
|
case HTTP_STATUS_IM_USED:
|
|
case HTTP_STATUS_MULTIPLE_CHOICES:
|
|
case HTTP_STATUS_MOVED_PERMANENTLY:
|
|
case HTTP_STATUS_FOUND:
|
|
case HTTP_STATUS_SEE_OTHER:
|
|
case HTTP_STATUS_NOT_MODIFIED:
|
|
case HTTP_STATUS_USE_PROXY:
|
|
case HTTP_STATUS_SWITCH_PROXY:
|
|
case HTTP_STATUS_TEMPORARY_REDIRECT:
|
|
case HTTP_STATUS_PERMANENT_REDIRECT:
|
|
case HTTP_STATUS_BAD_REQUEST:
|
|
case HTTP_STATUS_UNAUTHORIZED:
|
|
case HTTP_STATUS_FORBIDDEN:
|
|
case HTTP_STATUS_NOT_FOUND:
|
|
case HTTP_STATUS_METHOD_NOT_ALLOWED:
|
|
case HTTP_STATUS_NOT_ACCEPTABLE: /* With the Accept Req Hdr */
|
|
case HTTP_STATUS_PROXY_AUTHENTICATION_REQUIRED:
|
|
case HTTP_STATUS_REQUEST_TIMEOUT:
|
|
case HTTP_STATUS_CONFLICT:
|
|
case HTTP_STATUS_GONE:
|
|
case HTTP_STATUS_LENGTH_REQUIRED:
|
|
case HTTP_STATUS_PRECONDITION_FAILED:
|
|
case HTTP_STATUS_REQUEST_ENTITY_TOO_LARGE:
|
|
case HTTP_STATUS_REQUEST_URI_TOO_LONG:
|
|
case HTTP_STATUS_UNSUPPORTED_MEDIA_TYPE:
|
|
case HTTP_STATUS_REQUESTED_RANGE_NOT_SATISFIABLE:
|
|
case HTTP_STATUS_EXPECTATION_FAILED:
|
|
case HTTP_STATUS_MISDIRECTED_REQUEST:
|
|
case HTTP_STATUS_UNPROCESSABLE_ENTITY:
|
|
case HTTP_STATUS_LOCKED:
|
|
case HTTP_STATUS_FAILED_DEPENDENCY:
|
|
case HTTP_STATUS_UPGRADE_REQUIRED:
|
|
case HTTP_STATUS_PRECONDITION_REQUIRED:
|
|
case HTTP_STATUS_TOO_MANY_REQUESTS:
|
|
case HTTP_STATUS_REQUEST_HEADER_FIELDS_TOO_LARGE:
|
|
case HTTP_STATUS_UNAVAILABLE_FOR_LEGAL_REASONS:
|
|
case HTTP_STATUS_INTERNAL_SERVER_ERR:
|
|
case HTTP_STATUS_NOT_IMPLEMENTED:
|
|
case HTTP_STATUS_BAD_GATEWAY:
|
|
case HTTP_STATUS_SERVICE_UNAVAILABLE:
|
|
case HTTP_STATUS_GATEWAY_TIMEOUT:
|
|
case HTTP_STATUS_HTTP_VERSION_NOT_SUPPORTED:
|
|
case HTTP_STATUS_VARIANT_ALSO_NEGOTIATES:
|
|
case HTTP_STATUS_INSUFFICIENT_STORAGE:
|
|
case HTTP_STATUS_LOOP_DETECTED:
|
|
case HTTP_STATUS_NOT_EXTENDED:
|
|
case HTTP_STATUS_NETWORK_AUTHENTICATION_REQUIRED:
|
|
break;
|
|
|
|
|
|
case HTTP_STATUS_UNKNOWN:
|
|
default:
|
|
*p_err = HTTPc_ERR_RESP_STATUS_CODE_INVALID;
|
|
return;
|
|
}
|
|
|
|
/* ------------ FIND SPACE IN STATUS LINE ------------- */
|
|
p_resp_line_start = Str_Char_N(p_resp_line_start, len, ASCII_CHAR_SPACE);
|
|
if (p_resp_line_start == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_RESP_FORMAT_INVALID;
|
|
return;
|
|
}
|
|
p_resp_line_start++;
|
|
len = p_resp_line_end - p_resp_line_start;
|
|
|
|
/* ----------- PARSE RESPONSE REASON PHRASE ----------- */
|
|
p_resp->ReasonPhrasePtr = HTTPcResp_ParseReasonPhrase(p_resp_line_start, len, p_resp->StatusCode);
|
|
if (p_resp->ReasonPhrasePtr == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_RESP_REASON_PHRASE_INVALID;
|
|
return;
|
|
}
|
|
|
|
/* -------------- UPDATE CONN RX PARAMS --------------- */
|
|
p_resp_line_end += STR_CR_LF_LEN;
|
|
p_conn->RxDataLenRem -= (p_resp_line_end - p_conn->RxBufPtr);
|
|
p_conn->RxBufPtr = p_resp_line_end;
|
|
|
|
*p_err = HTTPc_ERR_NONE;
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* HTTPcResp_ParseProtocolVer()
|
|
*
|
|
* Description : Find HTTP Protocol version in the HTTP response received.
|
|
*
|
|
* Argument(s) : p_resp_line Pointer to Response status line received.
|
|
*
|
|
* str_len Length of the response status line.
|
|
*
|
|
* Return(s) : HTTP protocol version.
|
|
*
|
|
* Caller(s) : HTTPcResp_ParseStatusLine().
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static HTTP_PROTOCOL_VER HTTPcResp_ParseProtocolVer(const CPU_CHAR *p_resp_line,
|
|
CPU_INT32U str_len)
|
|
{
|
|
HTTP_PROTOCOL_VER ver;
|
|
|
|
ver = (HTTP_PROTOCOL_VER)HTTP_Dict_KeyGet(HTTP_Dict_ProtocolVer,
|
|
HTTP_Dict_ProtocolVerSize,
|
|
p_resp_line,
|
|
DEF_YES,
|
|
str_len);
|
|
switch (ver) {
|
|
case HTTP_PROTOCOL_VER_0_9:
|
|
case HTTP_PROTOCOL_VER_1_0:
|
|
case HTTP_PROTOCOL_VER_1_1:
|
|
break;
|
|
|
|
default:
|
|
return (HTTP_PROTOCOL_VER_UNKNOWN);
|
|
}
|
|
|
|
return ((HTTP_PROTOCOL_VER)ver);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* HTTPcResp_ParseStatusCode()
|
|
*
|
|
* Description : Find HTTP Status Code in the HTTP Response received.
|
|
*
|
|
* Argument(s) : p_resp_line Pointer to the HTTP Response status line received.
|
|
*
|
|
* str_len Length of the Response status line.
|
|
*
|
|
* Return(s) : HTTP status code.
|
|
*
|
|
* Caller(s) : HTTPcResp_ParseStatusLine().
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static HTTP_STATUS_CODE HTTPcResp_ParseStatusCode(const CPU_CHAR *p_resp_line,
|
|
CPU_INT32U str_len)
|
|
{
|
|
HTTP_STATUS_CODE status_code;
|
|
|
|
status_code = (HTTP_STATUS_CODE)HTTP_Dict_KeyGet(HTTP_Dict_StatusCode,
|
|
HTTP_Dict_StatusCodeSize,
|
|
p_resp_line,
|
|
DEF_YES,
|
|
str_len);
|
|
|
|
if (status_code >= HTTP_STATUS_UNKNOWN) {
|
|
return (HTTP_STATUS_UNKNOWN);
|
|
}
|
|
|
|
return (status_code);
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* HTTPcResp_ParseReasonPhrase()
|
|
*
|
|
* Description : Find HTTP Reason Phrase in the HTTP Response received.
|
|
*
|
|
* Argument(s) : p_resp_line Pointer to the HTTP Response status line received.
|
|
*
|
|
* str_len Length of the Response status line.
|
|
*
|
|
* status_code Status code number received.
|
|
*
|
|
* Return(s) : Pointer to the Reason phrase associated with the status code saved in the HTTP libraries.
|
|
*
|
|
* Caller(s) : HTTPcResp_ParseStatusLine().
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static const CPU_CHAR *HTTPcResp_ParseReasonPhrase(const CPU_CHAR *p_resp_line,
|
|
CPU_INT32U str_len,
|
|
HTTP_STATUS_CODE status_code)
|
|
{
|
|
HTTP_DICT *p_entry;
|
|
|
|
|
|
p_entry = HTTP_Dict_EntryGet(HTTP_Dict_ReasonPhrase,
|
|
HTTP_Dict_ReasonPhraseSize,
|
|
(CPU_INT32U)status_code);
|
|
|
|
return (p_entry->StrPtr);
|
|
}
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* HTTPcResp_ParseHdr()
|
|
*
|
|
* Description : Parse all the headers received in the HTTP response.
|
|
*
|
|
* Argument(s) : p_conn Pointer to the current HTTPc Connection.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* HTTPc_ERR_NONE Headers parsing successful.
|
|
* HTTPc_ERR_RESP_HDR_MALFORMED Malformed header received.
|
|
* HTTPc_ERR_RESP_HDR_INVALID Invalid arguments with header.
|
|
* HTTPc_ERR_TRANS_RX_MORE_DATA_REQUIRED More data needed.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Caller(s) : HTTPcResp().
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
/*解析http头部信息*/
|
|
static void HTTPcResp_ParseHdr(HTTPc_CONN *p_conn,
|
|
HTTPc_ERR *p_err)
|
|
{
|
|
HTTPc_REQ *p_req;
|
|
HTTPc_RESP *p_resp;
|
|
CPU_CHAR *p_field_start;
|
|
CPU_CHAR *p_field_end;
|
|
CPU_CHAR *p_val;
|
|
HTTP_HDR_FIELD hdr_field;
|
|
HTTP_HDR_FIELD_CONN_VAL hdr_con_val;
|
|
HTTP_CONTENT_TYPE content_type;
|
|
CPU_INT32U content_len;
|
|
HTTP_HDR_FIELD_TRANSFER_TYPE transfer_type;
|
|
CPU_INT16U len;
|
|
#if (HTTPc_CFG_HDR_RX_EN == DEF_ENABLED)
|
|
HTTPc_CONN_OBJ *p_conn_const;
|
|
HTTPc_REQ_OBJ *p_req_const;
|
|
HTTP_DICT *p_entry;
|
|
#endif
|
|
#ifdef HTTPc_WEBSOCK_MODULE_EN
|
|
HTTPc_WEBSOCK_REQ *p_ws_req;
|
|
CPU_BOOLEAN is_matched;
|
|
CPU_INT32U version;
|
|
#endif
|
|
|
|
/**********************************************/
|
|
printf(">>>>>>>>-------------------------------->>>>>>>>>>>>>>>>>%s, %d", __FUNCTION__, __LINE__);
|
|
httpcli_ctx *ctx = p_conn->UserData;
|
|
/**********************************************/
|
|
printf(">>>>>>>>-------------------------------->>>>>>>>>>>>>>>>>%s, %d", __FUNCTION__, __LINE__);
|
|
|
|
p_req = p_conn->ReqListHeadPtr;
|
|
p_resp = p_req->RespPtr;
|
|
|
|
p_field_start = p_conn->RxBufPtr;
|
|
#ifdef HTTPc_WEBSOCK_MODULE_EN
|
|
p_ws_req = p_req->WebSockPtr;
|
|
#endif
|
|
while (DEF_TRUE) {
|
|
|
|
p_field_end = Str_Str_N(p_field_start, /* Find end of header field. */
|
|
STR_CR_LF,
|
|
p_conn->RxDataLenRem);
|
|
|
|
if ((p_field_end != DEF_NULL) && /* If the field and value are present. */
|
|
(p_field_end > p_field_start)) {
|
|
|
|
len = p_field_end - p_field_start;
|
|
|
|
hdr_field = (HTTP_HDR_FIELD)HTTP_Dict_KeyGet(HTTP_Dict_HdrField,
|
|
HTTP_Dict_HdrFieldSize,
|
|
p_field_start,
|
|
DEF_NO,
|
|
len);
|
|
|
|
switch (hdr_field) {
|
|
case HTTP_HDR_FIELD_CONN:
|
|
/* Get field val beginning. */
|
|
p_val = HTTP_HdrParseFieldValueGet(p_field_start,
|
|
HTTP_STR_HDR_FIELD_CONN_LEN,
|
|
p_field_end,
|
|
&len);
|
|
if (p_val == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_RESP_HDR_MALFORMED;
|
|
goto exit;
|
|
}
|
|
|
|
len = p_field_end - p_val;
|
|
|
|
hdr_con_val = (HTTP_HDR_FIELD_CONN_VAL)HTTP_Dict_KeyGet(HTTP_Dict_HdrFieldConnVal,
|
|
HTTP_Dict_HdrFieldConnValSize,
|
|
p_val,
|
|
DEF_NO,
|
|
len);
|
|
switch (hdr_con_val) {
|
|
case HTTP_HDR_FIELD_CONN_CLOSE:
|
|
DEF_BIT_SET(p_conn->Flags, HTTPc_FLAG_CONN_TO_CLOSE);
|
|
p_conn->CloseStatus = HTTPc_CONN_CLOSE_STATUS_NO_PERSISTENT;
|
|
break;
|
|
|
|
case HTTP_HDR_FIELD_CONN_PERSISTENT:
|
|
break;
|
|
#ifdef HTTPc_WEBSOCK_MODULE_EN
|
|
case HTTP_HDR_FIELD_CONN_UPGRADE:
|
|
DEF_BIT_SET(p_ws_req->Flags, HTTPc_FLAG_WEBSOCK_REQ_CONN_UPGRADE);
|
|
break;
|
|
#endif
|
|
case HTTP_HDR_FIELD_CONN_UNKNOWN:
|
|
default:
|
|
*p_err = HTTPc_ERR_RESP_HDR_INVALID;
|
|
goto exit;
|
|
}
|
|
break;
|
|
|
|
|
|
case HTTP_HDR_FIELD_CONTENT_TYPE:
|
|
/* Get field val beginning. */
|
|
p_val = HTTP_HdrParseFieldValueGet(p_field_start,
|
|
HTTP_STR_HDR_FIELD_CONTENT_TYPE_LEN,
|
|
p_field_end,
|
|
&len);
|
|
if (p_val == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_RESP_HDR_MALFORMED;
|
|
goto exit;
|
|
}
|
|
|
|
len = p_field_end - p_val;
|
|
|
|
content_type = (HTTP_CONTENT_TYPE)HTTP_Dict_KeyGet(HTTP_Dict_ContentType,
|
|
HTTP_Dict_ContentTypeSize,
|
|
p_val,
|
|
DEF_NO,
|
|
len);
|
|
if (content_type == HTTP_CONTENT_TYPE_UNKNOWN) {
|
|
*p_err = HTTPc_ERR_RESP_CONTENT_TYPE_INVALID;
|
|
goto exit;
|
|
}
|
|
|
|
p_resp->ContentType = content_type;
|
|
break;
|
|
|
|
|
|
case HTTP_HDR_FIELD_CONTENT_LEN:
|
|
/* Get field val beginning. */
|
|
p_val = HTTP_HdrParseFieldValueGet(p_field_start,
|
|
HTTP_STR_HDR_FIELD_CONTENT_LEN_LEN,
|
|
p_field_end,
|
|
&len);
|
|
if (p_val == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_RESP_HDR_MALFORMED;
|
|
goto exit;
|
|
}
|
|
|
|
content_len = Str_ParseNbr_Int32U(p_val, 0, DEF_NBR_BASE_DEC);
|
|
|
|
if (content_len <= 0u) {
|
|
*p_err = HTTPc_ERR_RESP_CONTENT_LEN_INVALID;
|
|
goto exit;
|
|
}
|
|
|
|
p_resp->ContentLen = content_len;
|
|
/**************************************/
|
|
printf(">>>>>>>>-------------------------------->>>>>>>>>>>>>>>>>%s, %d", __FUNCTION__, __LINE__);
|
|
if (ctx != NULL) {
|
|
printf(">>>>>>>>-------------------------------->>>>>>>>>>>>>>>>>%s, %d", __FUNCTION__, __LINE__);
|
|
ctx->content_length = p_resp->ContentLen;
|
|
if (NULL != ctx->cb) {
|
|
printf(">>>>>>>>-------------------------------->>>>>>>>>>>>>>>>>%s, %d", __FUNCTION__, __LINE__);
|
|
ctx->cb(ctx, NULL, 0, ctx->priv, HTTPIN_HEADER);
|
|
}
|
|
}
|
|
|
|
printf(">>>>>>>>-------------------------------->>>>>>>>>>>>>>>>>%s, %d", __FUNCTION__, __LINE__);
|
|
/**************************************/
|
|
break;
|
|
|
|
|
|
case HTTP_HDR_FIELD_TRANSFER_ENCODING:
|
|
/* Get field val beginning. */
|
|
p_val = HTTP_HdrParseFieldValueGet(p_field_start,
|
|
HTTP_STR_HDR_FIELD_TRANSFER_ENCODING_LEN,
|
|
p_field_end,
|
|
&len);
|
|
if (p_val == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_RESP_HDR_MALFORMED;
|
|
goto exit;
|
|
}
|
|
|
|
len = p_field_end - p_val;
|
|
|
|
transfer_type = (HTTP_HDR_FIELD_TRANSFER_TYPE)HTTP_Dict_KeyGet(HTTP_Dict_HdrFieldTransferTypeVal,
|
|
HTTP_Dict_HdrFieldTransferTypeValSize,
|
|
p_val,
|
|
DEF_NO,
|
|
len);
|
|
if (transfer_type != HTTP_HDR_FIELD_TRANSFER_TYPE_CHUNKED) {
|
|
*p_err = HTTPc_ERR_RESP_HDR_INVALID;
|
|
goto exit;
|
|
}
|
|
DEF_BIT_SET(p_conn->RespFlags, HTTPc_FLAG_RESP_BODY_CHUNK_TRANSFER);
|
|
break;
|
|
|
|
#ifdef HTTPc_WEBSOCK_MODULE_EN
|
|
case HTTP_HDR_FIELD_UPGRADE:
|
|
/* Get field val beginning. */
|
|
p_val = HTTP_HdrParseFieldValueGet(p_field_start,
|
|
HTTP_STR_HDR_FIELD_UPGRADE_LEN,
|
|
p_field_end,
|
|
&len);
|
|
if (p_val == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_RESP_HDR_MALFORMED;
|
|
goto exit;
|
|
}
|
|
|
|
len = p_field_end - p_val;
|
|
|
|
hdr_con_val = (HTTP_HDR_FIELD_CONN_VAL)HTTP_Dict_KeyGet(HTTP_Dict_HdrFieldUpgradeVal,
|
|
HTTP_Dict_HdrFieldUpgradeValSize,
|
|
p_val,
|
|
DEF_NO,
|
|
len);
|
|
switch (hdr_con_val) {
|
|
case HTTP_HDR_FIELD_UPGRADE_WEBSOCKET:
|
|
DEF_BIT_SET(p_ws_req->Flags, HTTPc_FLAG_WEBSOCK_REQ_UPGRADE_WEBSOCKET);
|
|
break;
|
|
|
|
default:
|
|
*p_err = HTTPc_ERR_RESP_HDR_INVALID;
|
|
goto exit;
|
|
}
|
|
break;
|
|
|
|
|
|
case HTTP_HDR_FIELD_WEBSOCKET_ACCEPT:
|
|
/* Get field val beginning. */
|
|
p_val = HTTP_HdrParseFieldValueGet(p_field_start,
|
|
HTTP_STR_HDR_FIELD_WEBSOCKET_ACCEPT_LEN,
|
|
p_field_end,
|
|
&len);
|
|
if (p_val == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_RESP_HDR_MALFORMED;
|
|
goto exit;
|
|
}
|
|
|
|
len = p_field_end - p_val;
|
|
/* Validate the websocket field. */
|
|
|
|
is_matched = Mem_Cmp(p_ws_req->Accept, p_val, HTTPc_WEBSOCK_KEY_HASH_ENCODED_LEN - 1);
|
|
|
|
if (is_matched == DEF_YES) {
|
|
DEF_BIT_SET(p_ws_req->Flags, HTTPc_FLAG_WEBSOCK_REQ_ACCEPT_VALIDATED);
|
|
}
|
|
break;
|
|
|
|
|
|
case HTTP_HDR_FIELD_WEBSOCKET_VERSION:
|
|
/* Get field val beginning. */
|
|
p_val = HTTP_HdrParseFieldValueGet(p_field_start,
|
|
HTTP_STR_HDR_FIELD_WEBSOCKET_VERSION_LEN,
|
|
p_field_end,
|
|
&len);
|
|
if (p_val == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_RESP_HDR_MALFORMED;
|
|
goto exit;
|
|
}
|
|
version = Str_ParseNbr_Int32U(p_val, DEF_NULL, DEF_NBR_BASE_DEC);
|
|
|
|
if (version == HTTPc_WEBSOCK_PROTOCOL_VERSION_13) {
|
|
DEF_BIT_SET(p_ws_req->Flags, HTTPc_FLAG_WEBSOCK_REQ_VERSION_VALIDATED);
|
|
}
|
|
break;
|
|
#endif
|
|
|
|
default:
|
|
#if (HTTPc_CFG_HDR_RX_EN == DEF_ENABLED)
|
|
p_conn_const = (HTTPc_CONN_OBJ *)p_conn;
|
|
p_req_const = (HTTPc_REQ_OBJ *)p_req;
|
|
|
|
p_entry = HTTP_Dict_EntryGet(HTTP_Dict_HdrField,
|
|
HTTP_Dict_HdrFieldSize,
|
|
hdr_field);
|
|
if (p_entry != DEF_NULL) {
|
|
|
|
/* Get field val beginning. */
|
|
p_val = HTTP_HdrParseFieldValueGet(p_field_start,
|
|
p_entry->StrLen,
|
|
p_field_end,
|
|
&len);
|
|
if (p_val == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_RESP_HDR_MALFORMED;
|
|
goto exit;
|
|
}
|
|
|
|
len = p_field_end - p_val;
|
|
|
|
if (p_req->OnHdrRx != DEF_NULL) {
|
|
p_req->OnHdrRx(p_conn_const, p_req_const, hdr_field, p_val, len);
|
|
}
|
|
}
|
|
#endif
|
|
break;
|
|
}
|
|
|
|
/* --------------- UPDATE RX CONN PARAM --------------- */
|
|
p_field_end += STR_CR_LF_LEN;
|
|
p_conn->RxDataLenRem -= p_field_end - p_field_start;
|
|
p_field_start = p_field_end;
|
|
p_conn->RxBufPtr = p_field_start;
|
|
*p_err = HTTPc_ERR_NONE;
|
|
|
|
} else if (p_field_end == p_field_start) { /* All field processed. */
|
|
p_conn->RxBufPtr += STR_CR_LF_LEN;
|
|
p_conn->RxDataLenRem -= STR_CR_LF_LEN;
|
|
*p_err = HTTPc_ERR_NONE;
|
|
goto exit;
|
|
|
|
} else { /* More data req'd to complete processing. */
|
|
*p_err = HTTPc_ERR_TRANS_RX_MORE_DATA_REQUIRED;
|
|
goto exit;
|
|
}
|
|
|
|
}
|
|
|
|
|
|
exit:
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* HTTPcResp_Body()
|
|
*
|
|
* Description : Process Response body received.
|
|
*
|
|
* Argument(s) : p_conn Pointer to current HTTPc Connection.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* ------------ RETURNED BY HTTPcResp_BodyChunk() ------------
|
|
* See HTTPcResp_BodyChunk() for additional return error codes.
|
|
*
|
|
* ------------ RETURNED BY HTTPcResp_BodyStd() ------------
|
|
* See HTTPcResp_BodyStd() for additional return error codes.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Caller(s) : HTTPcResp().
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void HTTPcResp_Body(HTTPc_CONN *p_conn,
|
|
HTTPc_ERR *p_err)
|
|
{
|
|
CPU_BOOLEAN chunk_transfer;
|
|
|
|
|
|
chunk_transfer = DEF_BIT_IS_SET(p_conn->RespFlags, HTTPc_FLAG_RESP_BODY_CHUNK_TRANSFER);
|
|
if (chunk_transfer == DEF_YES) {
|
|
HTTPcResp_BodyChunk(p_conn, p_err);
|
|
} else {
|
|
HTTPcResp_BodyStd(p_conn, p_err);
|
|
}
|
|
}
|
|
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* HTTPcResp_BodyStd()
|
|
*
|
|
* Description : Process HTTP response body received with the Content-Length header.
|
|
*
|
|
* Argument(s) : p_conn Pointer to current HTTPc Connection.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* HTTPc_ERR_NONE Body successfully rx and process.
|
|
* HTTPc_ERR_RESP_RX_DATA_LEN_INVALID Invalid data length received.
|
|
* HTTPc_ERR_TRANS_RX_MORE_DATA_REQUIRED More data to received.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Caller(s) : HTTPcResp_Body().
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void HTTPcResp_BodyStd(HTTPc_CONN *p_conn,
|
|
HTTPc_ERR *p_err)
|
|
{
|
|
HTTPc_CONN_OBJ *p_conn_const;
|
|
HTTPc_REQ *p_req;
|
|
HTTPc_REQ_OBJ *p_req_const;
|
|
HTTPc_RESP *p_resp;
|
|
CPU_CHAR *p_buf;
|
|
CPU_INT32U content_len;
|
|
CPU_INT32U content_len_rem;
|
|
CPU_INT32U content_len_chunk;
|
|
CPU_INT32U data_len_read;
|
|
CPU_BOOLEAN last_chunk;
|
|
|
|
|
|
p_conn_const = (HTTPc_CONN_OBJ *)p_conn;
|
|
p_req = p_conn->ReqListHeadPtr;
|
|
p_req_const = (HTTPc_REQ_OBJ *)p_req;
|
|
p_resp = p_req->RespPtr;
|
|
content_len = p_resp->ContentLen;
|
|
p_buf = p_conn->RxBufPtr;
|
|
content_len_rem = content_len - p_conn->RxDataLen;
|
|
|
|
if (content_len_rem >= p_conn->RxDataLenRem) {
|
|
content_len_chunk = p_conn->RxDataLenRem;
|
|
} else {
|
|
content_len_chunk = content_len_rem;
|
|
}
|
|
p_conn->RxDataLen += content_len_chunk;
|
|
|
|
last_chunk = DEF_NO;
|
|
if (p_conn->RxDataLen == content_len) {
|
|
last_chunk = DEF_YES;
|
|
*p_err = HTTPc_ERR_NONE;
|
|
} else {
|
|
*p_err = HTTPc_ERR_TRANS_RX_MORE_DATA_REQUIRED;
|
|
}
|
|
|
|
|
|
if (p_req->OnBodyRx != DEF_NULL) {
|
|
data_len_read = p_req->OnBodyRx(p_conn_const,
|
|
p_req_const,
|
|
p_resp->ContentType,
|
|
p_buf,
|
|
content_len_chunk,
|
|
last_chunk);
|
|
p_conn->RxDataLen -= content_len_chunk - data_len_read;
|
|
p_conn->RxBufPtr += data_len_read;
|
|
p_conn->RxDataLenRem -= data_len_read;
|
|
|
|
} else {
|
|
p_conn->RxBufPtr += content_len_chunk;
|
|
p_conn->RxDataLenRem -= content_len_chunk;
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* HTTPcResp_BodyChunk()
|
|
*
|
|
* Description : Process Response body received with the chunked transfer encoding.
|
|
*
|
|
* Argument(s) : p_conn Pointer to current HTTPc Connection.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* HTTPc_ERR_NONE Body successfully received.
|
|
* HTTPc_ERR_TRANS_RX_MORE_DATA_REQUIRED More data to received.
|
|
* HTTPc_ERR_RESP_CHUNK_INVALID Invalid chunk received.
|
|
* HTTPc_ERR_CONN_INVALID_STATE Invalid Connection state.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Caller(s) : HTTPcResp_Body().
|
|
*
|
|
* Note(s) : (1) Chunk Extensions located after chunk size are not supported.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void HTTPcResp_BodyChunk(HTTPc_CONN *p_conn,
|
|
HTTPc_ERR *p_err)
|
|
{
|
|
HTTPc_CONN_OBJ *p_conn_const;
|
|
HTTPc_REQ *p_req;
|
|
HTTPc_REQ_OBJ *p_req_const;
|
|
HTTPc_RESP *p_resp;
|
|
CPU_CHAR *p_size_start;
|
|
CPU_CHAR *p_size_end;
|
|
CPU_CHAR *p_chunk_start;
|
|
CPU_CHAR *p_str;
|
|
CPU_INT32U chunk_len;
|
|
CPU_INT32U buf_len;
|
|
CPU_INT32U data_len;
|
|
CPU_INT32U data_len_read = 0;
|
|
|
|
|
|
p_conn_const = (HTTPc_CONN_OBJ *)p_conn;
|
|
p_req = p_conn->ReqListHeadPtr;
|
|
p_req_const = (HTTPc_REQ_OBJ *)p_req;
|
|
p_resp = p_req->RespPtr;
|
|
|
|
buf_len = p_conn->BufLen - p_conn->RxDataLenRem;
|
|
|
|
while (DEF_TRUE) {
|
|
switch (p_conn->State) {
|
|
case HTTPc_CONN_STATE_RESP_BODY:
|
|
case HTTPc_CONN_STATE_RESP_BODY_CHUNK_SIZE:
|
|
p_size_start = p_conn->RxBufPtr;
|
|
|
|
p_size_end = Str_Str_N(p_size_start, /* Find end of size of chunk. */
|
|
STR_CR_LF,
|
|
p_conn->RxDataLenRem);
|
|
if (p_size_end == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_TRANS_RX_MORE_DATA_REQUIRED;
|
|
goto exit;
|
|
}
|
|
/* Convert the hexadecimal string to 32 bits integer. */
|
|
chunk_len = Str_ParseNbr_Int32U(p_size_start, &p_str, 16);
|
|
if (p_str == p_size_start) {
|
|
*p_err = HTTPc_ERR_RESP_CHUNK_INVALID;
|
|
goto exit;
|
|
}
|
|
|
|
p_conn->RxDataLen = chunk_len;
|
|
|
|
p_size_end += STR_CR_LF_LEN;
|
|
p_conn->RxDataLenRem -= p_size_end - p_size_start;
|
|
p_conn->RxBufPtr = p_size_end;
|
|
|
|
if (chunk_len == 0) {
|
|
p_conn->State = HTTPc_CONN_STATE_RESP_BODY_CHUNK_LAST;
|
|
} else {
|
|
p_conn->State = HTTPc_CONN_STATE_RESP_BODY_CHUNK_DATA;
|
|
}
|
|
break;
|
|
|
|
|
|
case HTTPc_CONN_STATE_RESP_BODY_CHUNK_DATA:
|
|
p_chunk_start = p_conn->RxBufPtr;
|
|
/* If data in the buffer is less than the chunk length. */
|
|
if (p_conn->RxDataLenRem < p_conn->RxDataLen) {
|
|
if (buf_len > 0) { /* Buffer not full, go get more data. */
|
|
*p_err = HTTPc_ERR_TRANS_RX_MORE_DATA_REQUIRED;
|
|
goto exit;
|
|
} else {
|
|
data_len = p_conn->RxDataLenRem; /* Part of chunk received in buffer. */
|
|
}
|
|
} else {
|
|
data_len = p_conn->RxDataLen; /* End of chunk received in buffer. */
|
|
}
|
|
|
|
if (p_req->OnBodyRx != DEF_NULL) {
|
|
/* Pass data rx to application. */
|
|
data_len_read = p_req->OnBodyRx(p_conn_const,
|
|
p_req_const,
|
|
p_resp->ContentType,
|
|
p_conn->RxBufPtr,
|
|
data_len,
|
|
DEF_NO);
|
|
} else {
|
|
data_len_read = data_len;
|
|
}
|
|
|
|
p_conn->RxDataLenRem -= data_len_read;
|
|
p_conn->RxBufPtr = p_chunk_start + data_len_read;
|
|
p_conn->RxDataLen -= data_len_read;
|
|
|
|
if (p_conn->RxDataLenRem >= p_conn->RxDataLen) {
|
|
if (data_len_read >= data_len) {
|
|
p_conn->State = HTTPc_CONN_STATE_RESP_BODY_CHUNK_CRLF;
|
|
}
|
|
} else {
|
|
*p_err = HTTPc_ERR_TRANS_RX_MORE_DATA_REQUIRED;
|
|
goto exit;
|
|
}
|
|
break;
|
|
|
|
|
|
case HTTPc_CONN_STATE_RESP_BODY_CHUNK_CRLF:
|
|
if (p_conn->RxDataLenRem < STR_CR_LF_LEN) {
|
|
*p_err = HTTPc_ERR_TRANS_RX_MORE_DATA_REQUIRED;
|
|
goto exit;
|
|
}
|
|
|
|
p_str = Str_Str_N(p_conn->RxBufPtr, /* Find end of header field. */
|
|
STR_CR_LF,
|
|
p_conn->RxDataLenRem);
|
|
if (p_str == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_RESP_CHUNK_INVALID;
|
|
goto exit;
|
|
}
|
|
|
|
p_conn->RxDataLenRem -= STR_CR_LF_LEN;
|
|
p_conn->RxBufPtr += STR_CR_LF_LEN;
|
|
p_conn->State = HTTPc_CONN_STATE_RESP_BODY_CHUNK_SIZE;
|
|
break;
|
|
|
|
|
|
case HTTPc_CONN_STATE_RESP_BODY_CHUNK_LAST:
|
|
if (p_req->OnBodyRx != DEF_NULL) {
|
|
(void)p_req->OnBodyRx(p_conn_const,
|
|
p_req_const,
|
|
p_resp->ContentType,
|
|
DEF_NULL,
|
|
0,
|
|
DEF_YES);
|
|
}
|
|
p_conn->State = HTTPc_CONN_STATE_RESP_COMPLETED;
|
|
*p_err = HTTPc_ERR_NONE;
|
|
goto exit;
|
|
|
|
|
|
default:
|
|
*p_err = HTTPc_ERR_CONN_INVALID_STATE;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
return;
|
|
}
|