doubao_chat/lib/net/uC-HTTPc/Client/Source/http-c_resp.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;
}