3324 lines
128 KiB
C
3324 lines
128 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 REQUEST MODULE
|
|
*
|
|
* Filename : http-c_req.c
|
|
* Version : V3.01.00
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
* INCLUDE FILES
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
*/
|
|
#define MICRIUM_SOURCE
|
|
#define HTTPc_REQ_MODULE
|
|
|
|
#include <net_ascii.h>
|
|
#include <net_util.h>
|
|
|
|
#include "http-c_req.h"
|
|
#include "http-c_conn.h"
|
|
#include "http-c_sock.h"
|
|
#ifdef HTTPc_WEBSOCK_MODULE_EN
|
|
#include "http-c_websock.h"
|
|
#endif
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
* LOCAL FUNCTION PROTOTYPES
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
|
|
#if (HTTPc_CFG_FORM_EN == DEF_ENABLED)
|
|
static CPU_SIZE_T HTTPcReq_PrepareFormAppLen(HTTPc_CONN *p_conn,
|
|
HTTPc_ERR *p_err);
|
|
|
|
static CPU_SIZE_T HTTPcReq_PrepareFormMultipartLen(HTTPc_CONN *p_conn,
|
|
HTTPc_ERR *p_err);
|
|
#endif
|
|
|
|
static void HTTPcReq_Line(HTTPc_CONN *p_conn,
|
|
HTTPc_ERR *p_err);
|
|
|
|
#if (HTTPc_CFG_QUERY_STR_EN == DEF_ENABLED)
|
|
static CPU_CHAR *HTTPcReq_QueryStrTbl(HTTPc_CONN *p_conn,
|
|
CPU_CHAR *p_buf,
|
|
CPU_INT16U buf_len_rem,
|
|
HTTPc_ERR *p_err);
|
|
|
|
static CPU_CHAR *HTTPcReq_QueryStrHook(HTTPc_CONN *p_conn,
|
|
CPU_CHAR *p_buf,
|
|
CPU_INT16U buf_len_rem,
|
|
HTTPc_ERR *p_err);
|
|
#endif
|
|
|
|
static void HTTPcReq_Hdr(HTTPc_CONN *p_conn,
|
|
HTTPc_ERR *p_err);
|
|
|
|
#if (HTTPc_CFG_HDR_TX_EN == DEF_ENABLED)
|
|
static CPU_CHAR *HTTPcReq_HdrExtTbl(HTTPc_CONN *p_conn,
|
|
CPU_CHAR *p_buf,
|
|
CPU_INT16U buf_len_rem,
|
|
HTTPc_ERR *p_err);
|
|
|
|
static CPU_CHAR *HTTPcReq_HdrExtHook(HTTPc_CONN *p_conn,
|
|
CPU_CHAR *p_buf,
|
|
CPU_INT16U buf_len_rem,
|
|
HTTPc_ERR *p_err);
|
|
|
|
static HTTPc_HDR *HTTPcReq_HdrSearch(HTTPc_CONN *p_conn,
|
|
HTTP_HDR_FIELD hdr_field);
|
|
#endif
|
|
|
|
static void HTTPcReq_Body(HTTPc_CONN *p_conn,
|
|
HTTPc_ERR *p_err);
|
|
#if (HTTPc_CFG_FORM_EN == DEF_ENABLED)
|
|
static void HTTPcReq_FormApp(HTTPc_CONN *p_conn,
|
|
HTTPc_ERR *p_err);
|
|
|
|
static void HTTPcReq_FormMultipart(HTTPc_CONN *p_conn,
|
|
HTTPc_ERR *p_err);
|
|
#endif
|
|
|
|
static void HTTPcReq_BodyData(HTTPc_CONN *p_conn,
|
|
HTTPc_ERR *p_err);
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* HTTPcReq_Prepare()
|
|
*
|
|
* Description : (1) Additional preparation before request processing. Sets which HTTP mandatory headers to
|
|
* include:
|
|
*
|
|
* (a) Host
|
|
* (b) Connection
|
|
* (c) Content-Type
|
|
* (d) Content-Length
|
|
* (e) Transfer-Encoding
|
|
*
|
|
* (2) In case form table is present, calculate form size for 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 Request preparation successful
|
|
* HTTPc_ERR_REQ_HDR_UNAUTHORIZED Hdr in ext tbl must only be set by core.
|
|
* HTTPc_ERR_REQ_BODY_INVALID Invalid body/form ptr set by app.
|
|
* HTTPc_ERR_REQ_TRANSFER_ENCODING_INVALID Invalid transfer-encoding set by app.
|
|
* HTTPc_ERR_REQ_CONTENT_TYPE_INVALID Invalid content-type set by app.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Caller(s) : HTTPcTask_Handler().
|
|
*
|
|
* Note(s) : (1) The following HTTP headers must not be passed inside the extra header table. They
|
|
* will be set by the HTTP client core according to the arguments passed by the API
|
|
* functions :
|
|
* (a) Host
|
|
* (b) Connection
|
|
* (c) Content-Type
|
|
* (d) Content-Length
|
|
* (e) Transfer-Encoding
|
|
*
|
|
* (2) The Host Header is mandatory for HTTP/1.1 protocol version communication.
|
|
*
|
|
* (3) If a body is present in the request, one of the bellow header MUST be present :
|
|
* (a) Transfer-Encoding
|
|
* (b) Content-Length
|
|
*
|
|
* (4) Chunk Transfer-Encoding is only available in HTTP/1.1.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
void HTTPcReq_Prepare(HTTPc_CONN *p_conn,
|
|
HTTPc_ERR *p_err)
|
|
{
|
|
#if (HTTPc_CFG_HDR_TX_EN == DEF_ENABLED)
|
|
HTTPc_HDR *p_hdr;
|
|
#endif
|
|
HTTPc_REQ *p_req;
|
|
HTTP_DICT *p_entry;
|
|
CPU_BOOLEAN persistent;
|
|
CPU_BOOLEAN chunk_en;
|
|
CPU_BOOLEAN body_present;
|
|
CPU_BOOLEAN form_present;
|
|
#ifdef HTTPc_TASK_MODULE_EN
|
|
CPU_BOOLEAN no_block;
|
|
#endif
|
|
#ifdef HTTPc_WEBSOCK_MODULE_EN
|
|
CPU_BOOLEAN websocket;
|
|
#endif
|
|
|
|
p_req = p_conn->ReqListHeadPtr;
|
|
|
|
persistent = DEF_BIT_IS_SET(p_conn->Flags, HTTPc_FLAG_CONN_PERSISTENT);
|
|
chunk_en = DEF_BIT_IS_SET(p_req->Flags, HTTPc_FLAG_REQ_BODY_CHUNK_TRANSFER);
|
|
body_present = DEF_BIT_IS_SET(p_req->Flags, HTTPc_FLAG_REQ_BODY_PRESENT);
|
|
form_present = DEF_BIT_IS_SET(p_req->Flags, HTTPc_FLAG_REQ_FORM_PRESENT);
|
|
#ifdef HTTPc_WEBSOCK_MODULE_EN
|
|
websocket = DEF_BIT_IS_SET(p_req->Flags, HTTPc_FLAG_REQ_UPGRADE_WEBSOCKET);
|
|
#endif
|
|
/* -------------- VALIDATE QUERY STRING --------------- */
|
|
#if (HTTPc_CFG_QUERY_STR_EN == DEF_ENABLED)
|
|
|
|
if ((p_req->QueryStrNbr > 0) &&
|
|
(p_req->QueryStrTbl == DEF_NULL)) {
|
|
*p_err = HTTPc_ERR_REQ_PARAM_QUERY_STR_TBL_INVALID;
|
|
goto exit;
|
|
}
|
|
#endif
|
|
|
|
/* ----------- VALIDATE ADDITIONAL HEADERS ------------ */
|
|
#if (HTTPc_CFG_HDR_TX_EN == DEF_ENABLED)
|
|
if ((p_req->HdrNbr > 0) &&
|
|
(p_req->HdrTbl == DEF_NULL)) {
|
|
*p_err = HTTPc_ERR_REQ_PARAM_HDR_INVALID_TBL_PTR;
|
|
goto exit;
|
|
}
|
|
#endif
|
|
|
|
#if (HTTPc_CFG_FORM_EN == DEF_ENABLED)
|
|
if ((p_req->DataPtr != DEF_NULL) && /* Cannot have a body pointer and a form pointer at ... */
|
|
(p_req->FormFieldTbl != DEF_NULL)) { /* ... same time. */
|
|
*p_err = HTTPc_ERR_REQ_PARAM_BODY_INVALID;
|
|
goto exit;
|
|
}
|
|
#endif
|
|
|
|
/* -------------- VALIDATE REQUEST BODY --------------- */
|
|
if (body_present == DEF_YES) {
|
|
|
|
p_entry = HTTP_Dict_EntryGet(HTTP_Dict_ContentType,
|
|
HTTP_Dict_ContentTypeSize,
|
|
p_req->ContentType);
|
|
if (p_entry == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_PARAM_CONTENT_TYPE_INVALID;
|
|
goto exit;
|
|
}
|
|
|
|
if (form_present == DEF_NO) {
|
|
|
|
if ((chunk_en == DEF_NO) &&
|
|
(p_req->ContentLen == 0u)) {
|
|
*p_err = HTTPc_ERR_REQ_PARAM_CONTENT_LEN_INVALID;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
}
|
|
|
|
/* -------------- VALIDATE REQUEST FORM --------------- */
|
|
if (form_present == DEF_YES) {
|
|
#if (HTTPc_CFG_FORM_EN == DEF_ENABLED)
|
|
switch (p_req->ContentType) {
|
|
case HTTP_CONTENT_TYPE_APP_FORM:
|
|
case HTTP_CONTENT_TYPE_MULTIPART_FORM:
|
|
break;
|
|
|
|
|
|
default:
|
|
*p_err = HTTPc_ERR_REQ_PARAM_CONTENT_TYPE_INVALID;
|
|
goto exit;
|
|
}
|
|
|
|
if ((p_req->FormFieldNbr > 0) &&
|
|
(p_req->FormFieldTbl == DEF_NULL)) {
|
|
*p_err = HTTPc_ERR_REQ_PARAM_FORM_FIELD_TBL_INVALID;
|
|
goto exit;
|
|
}
|
|
#else
|
|
*p_err = HTTPc_ERR_FEATURE_DIS;
|
|
goto exit;
|
|
#endif
|
|
}
|
|
|
|
/* ---------------- VALIDATE CALLBACKS ---------------- */
|
|
#ifdef HTTPc_TASK_MODULE_EN
|
|
no_block = DEF_BIT_IS_SET(p_req->Flags, HTTPc_FLAG_REQ_NO_BLOCK);
|
|
if (no_block == DEF_YES) {
|
|
if (p_req->OnTransComplete == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_PARAM_TRANS_COMPLETE_CALLBACK_INVALID;
|
|
goto exit;
|
|
}
|
|
if (p_req->OnErr == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_PARAM_ERR_CALLBACK_INVALID;
|
|
goto exit;
|
|
}
|
|
}
|
|
#endif
|
|
|
|
/* ------ VALIDATE HTTP HEADERS RELATED TO CONN ------- */
|
|
/* HOST HEADER CASE. */
|
|
/* See Note #2. */
|
|
#if (HTTPc_CFG_HDR_TX_EN == DEF_ENABLED)
|
|
p_hdr = HTTPcReq_HdrSearch(p_conn, /* Search Host header in header list. */
|
|
HTTP_HDR_FIELD_HOST);
|
|
if (p_hdr != DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_PARAM_HDR_UNAUTHORIZED; /* See Note #1. */
|
|
goto exit;
|
|
}
|
|
#endif
|
|
DEF_BIT_SET(p_req->HdrFlags, HTTPc_FLAG_REQ_HDR_HOST_ADD);
|
|
|
|
/* WEBSOCKET CASE. */
|
|
#ifdef HTTPc_WEBSOCK_MODULE_EN
|
|
if (websocket == DEF_YES) {
|
|
p_hdr = HTTPcReq_HdrSearch(p_conn, /* Search Connection header in header list. */
|
|
HTTP_HDR_FIELD_CONN);
|
|
if (p_hdr != DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_PARAM_HDR_UNAUTHORIZED; /* See Note #1. */
|
|
goto exit;
|
|
}
|
|
DEF_BIT_SET(p_req->HdrFlags, HTTPc_FLAG_REQ_HDR_CONNECTION_ADD);
|
|
DEF_BIT_SET(p_req->HdrFlags, HTTPc_FLAG_REQ_HDR_UPGRADE_ADD);
|
|
DEF_BIT_SET(p_req->HdrFlags, HTTPc_FLAG_REQ_HDR_WEBSOCKET_ADD);
|
|
}
|
|
#endif
|
|
|
|
/* CONNECTION HEADER CASE. */
|
|
#ifdef HTTPc_WEBSOCK_MODULE_EN
|
|
if ((persistent == DEF_NO) && (websocket == DEF_NO)) {
|
|
#else
|
|
if (persistent == DEF_NO) {
|
|
#endif
|
|
#if (HTTPc_CFG_HDR_TX_EN == DEF_ENABLED)
|
|
p_hdr = HTTPcReq_HdrSearch(p_conn, /* Search Connection header in header list. */
|
|
HTTP_HDR_FIELD_CONN);
|
|
if (p_hdr != DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_PARAM_HDR_UNAUTHORIZED; /* See Note #1. */
|
|
goto exit;
|
|
}
|
|
#endif
|
|
DEF_BIT_SET(p_req->HdrFlags, HTTPc_FLAG_REQ_HDR_CONNECTION_ADD);
|
|
DEF_BIT_SET(p_conn->Flags, HTTPc_FLAG_CONN_TO_CLOSE);
|
|
p_conn->CloseStatus = HTTPc_CONN_CLOSE_STATUS_NO_PERSISTENT;
|
|
}
|
|
|
|
/* ------ VALIDATE HTTP HEADERS RELATED TO BODY ------- */
|
|
if (body_present == DEF_YES) {
|
|
/* CONTENT-TYPE HEADER CASE. */
|
|
#if (HTTPc_CFG_HDR_TX_EN == DEF_ENABLED)
|
|
p_hdr = HTTPcReq_HdrSearch(p_conn, /* Search Content-Type header in header list. */
|
|
HTTP_HDR_FIELD_CONTENT_TYPE);
|
|
if (p_hdr != DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_PARAM_HDR_UNAUTHORIZED; /* See Note #1. */
|
|
goto exit;
|
|
}
|
|
#endif
|
|
|
|
DEF_BIT_SET(p_req->HdrFlags, HTTPc_FLAG_REQ_HDR_CONTENT_TYPE_ADD);
|
|
|
|
/* TRANSFER-ENCODING HEADER CASE. */
|
|
#if (HTTPc_CFG_HDR_TX_EN == DEF_ENABLED)
|
|
p_hdr = HTTPcReq_HdrSearch(p_conn, /* Search Transfer-Encoding header in header list. */
|
|
HTTP_HDR_FIELD_TRANSFER_ENCODING);
|
|
if (p_hdr != DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_PARAM_HDR_UNAUTHORIZED; /* See Note #1. */
|
|
goto exit;
|
|
}
|
|
#endif
|
|
|
|
if (chunk_en == DEF_YES) {
|
|
DEF_BIT_SET(p_req->HdrFlags, HTTPc_FLAG_REQ_HDR_TRANSFER_ENCODE_ADD);
|
|
}
|
|
|
|
/* CONTENT-LENGTH HEADER CASE. */
|
|
#if (HTTPc_CFG_HDR_TX_EN == DEF_ENABLED)
|
|
p_hdr = HTTPcReq_HdrSearch(p_conn, /* Search Content-Length header in header list. */
|
|
HTTP_HDR_FIELD_CONTENT_LEN);
|
|
if (p_hdr != DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_PARAM_HDR_UNAUTHORIZED; /* See Note #1. */
|
|
goto exit;
|
|
}
|
|
#endif
|
|
|
|
if (p_req->ContentLen > 0u) {
|
|
DEF_BIT_SET(p_req->HdrFlags, HTTPc_FLAG_REQ_HDR_CONTENT_LENGTH_ADD);
|
|
}
|
|
|
|
|
|
#if (HTTPc_CFG_FORM_EN == DEF_ENABLED)
|
|
/* - CALCULATE FORM LENGTH FOR CONTENT-LENGTH HEADER -- */
|
|
if (form_present == DEF_YES) {
|
|
|
|
DEF_BIT_SET(p_req->HdrFlags, HTTPc_FLAG_REQ_HDR_CONTENT_LENGTH_ADD);
|
|
|
|
switch (p_req->ContentType) {
|
|
case HTTP_CONTENT_TYPE_APP_FORM:
|
|
p_req->ContentLen = HTTPcReq_PrepareFormAppLen(p_conn, p_err);
|
|
break;
|
|
|
|
|
|
case HTTP_CONTENT_TYPE_MULTIPART_FORM:
|
|
p_req->ContentLen = HTTPcReq_PrepareFormMultipartLen(p_conn, p_err);
|
|
break;
|
|
|
|
|
|
default:
|
|
*p_err = HTTPc_ERR_REQ_PARAM_CONTENT_TYPE_INVALID;
|
|
goto exit;
|
|
}
|
|
|
|
DEF_BIT_CLR(p_req->HdrFlags, HTTPc_FLAG_REQ_HDR_TRANSFER_ENCODE_ADD);
|
|
}
|
|
#endif
|
|
}
|
|
|
|
*p_err = HTTPc_ERR_NONE;
|
|
|
|
|
|
exit:
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* HTTPcReq()
|
|
*
|
|
* Description : (1) Send data to TCP-IP stack if data is ready to be sent.
|
|
* (2) State Machine for the Request processing:
|
|
* (a) Prepare Request Line.
|
|
* (b) Prepare Headers.
|
|
* (c) Prepare Body.
|
|
*
|
|
*
|
|
* 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 HTTPcSock_ConnDataTx() ------------
|
|
* See HTTPcSock_ConnDataTx() for additional return error codes.
|
|
*
|
|
* ------------ RETURNED BY HTTPcReq_Line() ------------
|
|
* See HTTPcReq_Line() for additional return error codes.
|
|
*
|
|
* ------------ RETURNED BY HTTPcReq_Hdr() ------------
|
|
* See HTTPcReq_Hdr() for additional return error codes.
|
|
*
|
|
* ------------ RETURNED BY HTTPcReq_Body() ------------
|
|
* See HTTPcReq_Body() for additional return error codes.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Caller(s) : HTTPcTask_Handler().
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
/*修改,发送处理函数 */
|
|
CPU_BOOLEAN HTTPcReq(HTTPc_CONN *p_conn,
|
|
HTTPc_ERR *p_err)
|
|
{
|
|
CPU_BOOLEAN process;
|
|
CPU_BOOLEAN done;
|
|
CPU_BOOLEAN sock_rdy_wr;
|
|
CPU_BOOLEAN sock_rdy_err;
|
|
|
|
|
|
done = DEF_NO;
|
|
process = DEF_YES;
|
|
/* -------- PASS DATA TO SEND TO TCP-IP STACK --------- */
|
|
if (p_conn->TxDataLen > 0) {
|
|
/* sock_rdy_wr = DEF_BIT_IS_SET(p_conn->SockFlags, HTTPc_FLAG_SOCK_RDY_WR); */
|
|
/* sock_rdy_err = DEF_BIT_IS_SET(p_conn->SockFlags, HTTPc_FLAG_SOCK_RDY_ERR); */
|
|
|
|
/* if((sock_rdy_wr == DEF_YES) || */
|
|
/* (sock_rdy_err == DEF_YES)) { */
|
|
|
|
process = HTTPcSock_ConnDataTx(p_conn, p_err);
|
|
switch (*p_err) {
|
|
case HTTPc_ERR_NONE:
|
|
case HTTPc_ERR_CONN_SOCK_TX:
|
|
break;
|
|
|
|
default:
|
|
goto exit;
|
|
}
|
|
/* } */
|
|
|
|
}
|
|
/* -------- PROCESS INCOMING REQUEST FROM APP --------- */
|
|
if (process == DEF_YES) {
|
|
switch (p_conn->State) {
|
|
case HTTPc_CONN_STATE_REQ_LINE_METHOD:
|
|
case HTTPc_CONN_STATE_REQ_LINE_URI:
|
|
case HTTPc_CONN_STATE_REQ_LINE_QUERY_STR:
|
|
case HTTPc_CONN_STATE_REQ_LINE_PROTO_VER:
|
|
HTTPcReq_Line(p_conn, p_err); /* Prepare Request Line. */
|
|
break;
|
|
|
|
|
|
case HTTPc_CONN_STATE_REQ_HDR_HOST:
|
|
case HTTPc_CONN_STATE_REQ_HDR_CONTENT_TYPE:
|
|
case HTTPc_CONN_STATE_REQ_HDR_CONTENT_LEN:
|
|
case HTTPc_CONN_STATE_REQ_HDR_TRANSFER_ENCODE:
|
|
case HTTPc_CONN_STATE_REQ_HDR_CONN:
|
|
case HTTPc_CONN_STATE_REQ_HDR_EXT:
|
|
case HTTPc_CONN_STATE_REQ_HDR_LAST:
|
|
HTTPcReq_Hdr(p_conn, p_err); /* Prepare Request Headers. */
|
|
break;
|
|
|
|
|
|
case HTTPc_CONN_STATE_REQ_BODY:
|
|
case HTTPc_CONN_STATE_REQ_BODY_DATA:
|
|
case HTTPc_CONN_STATE_REQ_BODY_DATA_CHUNK_SIZE:
|
|
case HTTPc_CONN_STATE_REQ_BODY_DATA_CHUNK_DATA:
|
|
case HTTPc_CONN_STATE_REQ_BODY_DATA_CHUNK_END:
|
|
case HTTPc_CONN_STATE_REQ_BODY_FORM_APP:
|
|
case HTTPc_CONN_STATE_REQ_BODY_FORM_MULTIPART_BOUNDARY:
|
|
case HTTPc_CONN_STATE_REQ_BODY_FORM_MULTIPART_HDR_CONTENT_DISPO:
|
|
case HTTPc_CONN_STATE_REQ_BODY_FORM_MULTIPART_HDR_CONTENT_TYPE:
|
|
case HTTPc_CONN_STATE_REQ_BODY_FORM_MULTIPART_DATA:
|
|
case HTTPc_CONN_STATE_REQ_BODY_FORM_MULTIPART_DATA_END:
|
|
case HTTPc_CONN_STATE_REQ_BODY_FORM_MULTIPART_BOUNDARY_END:
|
|
HTTPcReq_Body(p_conn, p_err); /* Prepare Request Body. */
|
|
break;
|
|
|
|
|
|
case HTTPc_CONN_STATE_REQ_END:
|
|
*p_err = HTTPc_ERR_NONE;
|
|
if (p_conn->TxDataLen == 0u) { /* Validate Tx is completed before switch to Resp. */
|
|
done = DEF_YES;
|
|
p_conn->State = HTTPc_CONN_STATE_RESP_INIT;
|
|
}
|
|
break;
|
|
|
|
|
|
default:
|
|
*p_err = HTTPc_ERR_CONN_INVALID_STATE;
|
|
break;
|
|
}
|
|
}
|
|
|
|
exit:
|
|
return (done);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* HTTPcReq_HdrCopyToBuf()
|
|
*
|
|
* Description : Construct and Copy HTTP header to HTTP buffer.
|
|
*
|
|
* Argument(s) : p_buf Pointer to HTTP buffer.
|
|
*
|
|
* buf_len Length remaining in HTTP buffer.
|
|
*
|
|
* hdr_type HTTP header type.
|
|
*
|
|
* p_val Pointer to HTTP header value.
|
|
*
|
|
* val_len HTTP header value length.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* HTTPc_ERR_NONE Header copy to buffer successfully.
|
|
* HTTPc_ERR_REQ_HDR_INVALID Header field type not found in dictionary.
|
|
* HTTPc_ERR_REQ_HDR_CREATE Fatal error while creating header.
|
|
* HTTPc_ERR_TRANS_BUF_LEN_INVALID HTTP buffer length is not enough big.
|
|
* HTTPc_ERR_TRANS_TX_BUF_FULL HTTP buffer is full, data must be Tx.
|
|
*
|
|
* Return(s) : Pointer to location in HTTP buffer after data written.
|
|
*
|
|
* Caller(s) : HTTPcReq_Hdr().
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
CPU_CHAR *HTTPcReq_HdrCopyToBuf(CPU_CHAR *p_buf,
|
|
CPU_INT16U buf_len,
|
|
CPU_SIZE_T buf_len_rem,
|
|
HTTP_HDR_FIELD hdr_type,
|
|
const CPU_CHAR *p_val,
|
|
CPU_SIZE_T val_len,
|
|
CPU_BOOLEAN add_CRLF,
|
|
HTTPc_ERR *p_err)
|
|
{
|
|
HTTP_DICT *p_entry;
|
|
CPU_CHAR *p_str;
|
|
CPU_SIZE_T len_need;
|
|
|
|
|
|
p_str = p_buf;
|
|
|
|
/* Find Header type in dictionary. */
|
|
p_entry = HTTP_Dict_EntryGet(HTTP_Dict_HdrField,
|
|
HTTP_Dict_HdrFieldSize,
|
|
hdr_type);
|
|
if (p_entry == DEF_NULL) {
|
|
p_str = DEF_NULL;
|
|
*p_err = HTTPc_ERR_REQ_HDR_INVALID;
|
|
goto exit;
|
|
}
|
|
|
|
len_need = p_entry->StrLen + val_len + 2; /* Calculate length needed for header. */
|
|
if (add_CRLF == DEF_YES) {
|
|
len_need += STR_CR_LF_LEN;
|
|
}
|
|
|
|
if (len_need > buf_len) { /* Total len of hdr must be smaller than HTTP buf size. */
|
|
p_str = DEF_NULL;
|
|
*p_err = HTTPc_ERR_TRANS_BUF_LEN_INVALID;
|
|
goto exit;
|
|
}
|
|
|
|
if (len_need > buf_len_rem) { /* Missing space in HTTP buf. Data must be Tx. */
|
|
p_str = DEF_NULL;
|
|
*p_err = HTTPc_ERR_TRANS_TX_BUF_FULL;
|
|
goto exit;
|
|
}
|
|
/* Copy Header Type to buffer. */
|
|
p_str = Str_Copy_N(p_str, p_entry->StrPtr, p_entry->StrLen);
|
|
if (p_str == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_HDR_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
p_str += p_entry->StrLen;
|
|
|
|
*p_str = ASCII_CHAR_COLON; /* Copy ":" character to buffer. */
|
|
p_str++;
|
|
*p_str = ASCII_CHAR_SPACE; /* Copy space character to buffer. */
|
|
p_str++;
|
|
|
|
p_str = Str_Copy_N(p_str, p_val, val_len); /* Copy header value to buffer. */
|
|
if (p_str == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_HDR_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
p_str += val_len;
|
|
|
|
if (add_CRLF == DEF_YES) {
|
|
/* Copy end of line CRLN characters to buffer. */
|
|
p_str = Str_Copy_N(p_str, STR_CR_LF, STR_CR_LF_LEN);
|
|
if (p_str == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_HDR_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
p_str += STR_CR_LF_LEN;
|
|
}
|
|
|
|
*p_err = HTTPc_ERR_NONE;
|
|
|
|
|
|
exit:
|
|
return (p_str);
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
* LOCAL FUNCTIONS
|
|
*********************************************************************************************************
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* HTTPcReq_PrepareFormAppLen()
|
|
*
|
|
* Description : Calculate length of Application form by parsing form table passed by application.
|
|
*
|
|
* 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 Form size successfully calculate.
|
|
*
|
|
* Return(s) : Length of the application form.
|
|
* Length 0 in case of error.
|
|
*
|
|
* Caller(s) : HTTPcReq_Prepare().
|
|
*
|
|
* Note(s) : (1) In case form table is passed by application and Chunked Transfer is disabled, length
|
|
* of form must be calculate to put inside Content-Length header.
|
|
*
|
|
* (2) Application type Form must be URL-Encode.
|
|
*********************************************************************************************************
|
|
*/
|
|
#if (HTTPc_CFG_FORM_EN == DEF_ENABLED)
|
|
static CPU_SIZE_T HTTPcReq_PrepareFormAppLen(HTTPc_CONN *p_conn,
|
|
HTTPc_ERR *p_err)
|
|
{
|
|
HTTPc_REQ *p_req;
|
|
HTTPc_FORM_TBL_FIELD *p_form_tbl;
|
|
HTTPc_FORM_TBL_FIELD *p_tbl_entry;
|
|
HTTPc_KEY_VAL *p_kvp;
|
|
CPU_SIZE_T total_len;
|
|
CPU_INT16U char_encode_nbr;
|
|
CPU_INT16U i;
|
|
|
|
|
|
p_req = p_conn->ReqListHeadPtr;
|
|
|
|
p_form_tbl = (HTTPc_FORM_TBL_FIELD *)p_req->FormFieldTbl;
|
|
total_len = 0;
|
|
|
|
/* ----------- PARSE APPLICATION FORM TABLE ----------- */
|
|
for (i = 0; i < p_req->FormFieldNbr; i++) {
|
|
|
|
p_tbl_entry = &p_form_tbl[i];
|
|
|
|
switch (p_tbl_entry->Type) {
|
|
case HTTPc_FORM_FIELD_TYPE_KEY_VAL:
|
|
break;
|
|
|
|
|
|
case HTTPc_FORM_FIELD_TYPE_KEY_VAL_EXT:
|
|
case HTTPc_FORM_FIELD_TYPE_FILE:
|
|
default:
|
|
total_len = 0;
|
|
*p_err = HTTPc_ERR_FORM_TYPE_INVALID;
|
|
goto exit;
|
|
}
|
|
|
|
p_kvp = (HTTPc_KEY_VAL *)p_tbl_entry->FieldObjPtr;
|
|
|
|
char_encode_nbr = HTTP_URL_CharEncodeNbr(p_kvp->KeyPtr, p_kvp->KeyLen);
|
|
|
|
total_len += (p_kvp->KeyLen + char_encode_nbr * HTTP_URL_ENCODING_JUMP);
|
|
|
|
char_encode_nbr = HTTP_URL_CharEncodeNbr(p_kvp->ValPtr, p_kvp->ValLen);
|
|
|
|
total_len += (p_kvp->ValLen + char_encode_nbr * HTTP_URL_ENCODING_JUMP);
|
|
|
|
}
|
|
|
|
total_len += 2 * p_req->FormFieldNbr - 1; /* Add length of all "=" and "&" char to include ... */
|
|
/* ... in the form. */
|
|
|
|
*p_err = HTTPc_ERR_NONE;
|
|
|
|
|
|
exit:
|
|
return (total_len);
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* HTTPcReq_PrepareFormMultipartLen()
|
|
*
|
|
* Description : Calculate length of Multipart form by parsing form table passed by application.
|
|
*
|
|
* 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 Form size successfully calculate.
|
|
*
|
|
* Return(s) : Length of the application form.
|
|
* Length 0 in case of error.
|
|
*
|
|
* Caller(s) : HTTPcReq_Prepare().
|
|
*
|
|
* Note(s) : (1) In case form table is passed by application and Chunked Transfer is disabled, length
|
|
* of form must be calculate to put inside Content-Length header.
|
|
*********************************************************************************************************
|
|
*/
|
|
#if (HTTPc_CFG_FORM_EN == DEF_ENABLED)
|
|
static CPU_SIZE_T HTTPcReq_PrepareFormMultipartLen(HTTPc_CONN *p_conn,
|
|
HTTPc_ERR *p_err)
|
|
{
|
|
HTTPc_REQ *p_req;
|
|
HTTPc_FORM_TBL_FIELD *p_form_tbl;
|
|
HTTPc_FORM_TBL_FIELD *p_tbl_entry;
|
|
HTTPc_KEY_VAL *p_kvp;
|
|
HTTPc_KEY_VAL_EXT *p_kvp_big;
|
|
HTTPc_MULTIPART_FILE *p_multipart_file;
|
|
HTTP_DICT *p_entry;
|
|
CPU_SIZE_T total_len;
|
|
CPU_INT16U char_encode_nbr;
|
|
CPU_INT16U i;
|
|
|
|
|
|
p_req = p_conn->ReqListHeadPtr;
|
|
|
|
p_form_tbl = p_req->FormFieldTbl;
|
|
|
|
total_len = 0;
|
|
|
|
for (i = 0; i < p_req->FormFieldNbr; i++) {
|
|
|
|
p_tbl_entry = &p_form_tbl[i];
|
|
|
|
/* ----------- ADD LENGTH OF START BOUNDARY ----------- */
|
|
total_len += HTTPc_STR_BOUNDARY_START_LEN + STR_CR_LF_LEN;
|
|
|
|
/* ------ ADD LENGTH OF CONTENT-DISPOSITION HDR ------- */
|
|
total_len += HTTP_STR_HDR_FIELD_CONTENT_DISPOSITION_LEN +
|
|
2 +
|
|
HTTP_STR_CONTENT_DISPOSITION_FORM_DATA_LEN +
|
|
2 +
|
|
HTTP_STR_MULTIPART_FIELD_NAME_LEN +
|
|
3 +
|
|
STR_CR_LF_LEN;
|
|
|
|
switch (p_tbl_entry->Type) {
|
|
case HTTPc_FORM_FIELD_TYPE_KEY_VAL:
|
|
p_kvp = (HTTPc_KEY_VAL *)p_tbl_entry->FieldObjPtr;
|
|
/* Add length of Name field. */
|
|
char_encode_nbr = HTTP_URL_CharEncodeNbr(p_kvp->KeyPtr, p_kvp->KeyLen);
|
|
total_len += (p_kvp->KeyLen + char_encode_nbr * HTTP_URL_ENCODING_JUMP);
|
|
/* Add length of data. */
|
|
total_len += p_kvp->ValLen + 2 * STR_CR_LF_LEN;
|
|
break;
|
|
|
|
|
|
case HTTPc_FORM_FIELD_TYPE_KEY_VAL_EXT:
|
|
p_kvp_big = (HTTPc_KEY_VAL_EXT *)p_tbl_entry->FieldObjPtr;
|
|
/* Add length of Name field. */
|
|
char_encode_nbr = HTTP_URL_CharEncodeNbr(p_kvp_big->KeyPtr, p_kvp_big->KeyLen);
|
|
total_len += (p_kvp_big->KeyLen + char_encode_nbr * HTTP_URL_ENCODING_JUMP);
|
|
/* Add length of data. */
|
|
total_len += p_kvp_big->ValLen + 2 * STR_CR_LF_LEN;
|
|
break;
|
|
|
|
|
|
case HTTPc_FORM_FIELD_TYPE_FILE:
|
|
p_multipart_file = (HTTPc_MULTIPART_FILE *)p_tbl_entry->FieldObjPtr;
|
|
/* Add length of Name field. */
|
|
char_encode_nbr = HTTP_URL_CharEncodeNbr(p_multipart_file->NamePtr, p_multipart_file->NameLen);
|
|
total_len += (p_multipart_file->NameLen + char_encode_nbr * HTTP_URL_ENCODING_JUMP);
|
|
/* Add length of File Name field. */
|
|
char_encode_nbr = HTTP_URL_CharEncodeNbr(p_multipart_file->FileNamePtr, p_multipart_file->FileNameLen);
|
|
total_len += (p_multipart_file->FileNameLen + char_encode_nbr * HTTP_URL_ENCODING_JUMP);
|
|
total_len += 2 + HTTP_STR_MULTIPART_FIELD_FILE_NAME_LEN + 3;
|
|
/* Add length of Content-Type Header. */
|
|
p_entry = HTTP_Dict_EntryGet(HTTP_Dict_ContentType,
|
|
HTTP_Dict_ContentTypeSize,
|
|
p_multipart_file->ContentType);
|
|
if (p_entry != DEF_NULL) {
|
|
total_len += HTTP_STR_HDR_FIELD_CONTENT_TYPE_LEN +
|
|
2 +
|
|
p_entry->StrLen +
|
|
STR_CR_LF_LEN;
|
|
}
|
|
/* Add length of data. */
|
|
total_len += p_multipart_file->FileLen + 2 * STR_CR_LF_LEN;
|
|
break;
|
|
|
|
|
|
default:
|
|
total_len = 0;
|
|
*p_err = HTTPc_ERR_FORM_TYPE_INVALID;
|
|
goto exit;
|
|
}
|
|
|
|
}
|
|
|
|
/* ------------ ADD LENGTH OF END BOUNDARY ------------ */
|
|
total_len += HTTPc_STR_BOUNDARY_END_LEN + STR_CR_LF_LEN;
|
|
|
|
*p_err = HTTPc_ERR_NONE;
|
|
|
|
|
|
exit:
|
|
return (total_len);
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* HTTPcReq_Line()
|
|
*
|
|
* Description : (1) Prepare and Copy HTTP Request line to HTTP Tx buffer.
|
|
* (2) An HTTP line consist of :
|
|
* (a) Method
|
|
* (b) URI
|
|
* (c) Query String
|
|
* (d) Protocol Version
|
|
*
|
|
*
|
|
* 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 Req State successfully processed.
|
|
* HTTPc_ERR_REQ_LINE_CREATE Fatal error in the Req Line process.
|
|
* HTTPc_ERR_TRANS_BUF_LEN_INVALID HTTP buffer length is not enough big.
|
|
* HTTPc_ERR_TRANS_TX_BUF_FULL HTTP buffer is full, data must be Tx.
|
|
*
|
|
* ------------ RETURNED BY HTTPcReq_QueryStrTbl() ------------
|
|
* See HTTPcReq_QueryStrTbl() for additional return error codes.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Caller(s) : HTTPcReq().
|
|
*
|
|
* Note(s) : (3) HTTP Line parameters previously validate in API function HTTPc_SetReqLineParam().
|
|
*
|
|
* (4) The Request line processing is design as a state machine with 4 different states:
|
|
* HTTPc_CONN_STATE_REQ_LINE_METHOD
|
|
* HTTPc_CONN_STATE_REQ_LINE_URI
|
|
* HTTPc_CONN_STATE_REQ_LINE_QUERY_STR
|
|
* HTTPc_CONN_STATE_REQ_LINE_PROTO_VER
|
|
*
|
|
* (5) The data length of each state MUST be smaller than the configured HTTPc buffer length.
|
|
* Else the process is aborted and the err code HTTPc_ERR_TRANS_BUF_LEN_INVALID is returned.
|
|
* The buffer length MUST be reconfigured and increased.
|
|
* Exception for the URI, see Note #7.
|
|
* Exception for the Query String, see Note #8.
|
|
*
|
|
* (6) The function will not return until all the request line has been copied to the HTTP
|
|
* buffer or if the buffer is full before the end of the line processing. In that case,
|
|
* the state is saved and the function will exit to allow the data to be transmit.
|
|
* Next time around the process will resume at the saved state.
|
|
*
|
|
* (7) The URI can be bigger than the HTTP buffer length. In that case, the URI is not copied
|
|
* into the HTTP buffer, the pointer to the URI will be passed directly to the TCPI-IP
|
|
* stack.
|
|
*
|
|
* (8) See Note #1 of function HTTPcReq_QueryStrTbl() and HTTPcReq_QueryStrHook().
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void HTTPcReq_Line(HTTPc_CONN *p_conn,
|
|
HTTPc_ERR *p_err)
|
|
{
|
|
HTTPc_REQ *p_req;
|
|
HTTP_DICT *p_entry;
|
|
CPU_CHAR *p_buf;
|
|
CPU_CHAR *p_buf_wr_start;
|
|
CPU_CHAR *p_buf_wr_end;
|
|
CPU_SIZE_T buf_len;
|
|
CPU_SIZE_T str_len;
|
|
|
|
|
|
p_req = p_conn->ReqListHeadPtr;
|
|
|
|
p_buf = p_conn->TxBufPtr + p_conn->TxDataLen;
|
|
buf_len = p_conn->BufLen - p_conn->TxDataLen;
|
|
p_buf_wr_start = p_buf;
|
|
p_buf_wr_end = p_buf;
|
|
|
|
switch (p_conn->State) {
|
|
case HTTPc_CONN_STATE_REQ_LINE_METHOD:
|
|
/* -------------- PREPARE REQ LINE METHOD-------------- */
|
|
/* Find Method in HTTP dictionary. */
|
|
p_entry = HTTP_Dict_EntryGet(HTTP_Dict_ReqMethod,
|
|
HTTP_Dict_ReqMethodSize,
|
|
p_req->Method);
|
|
if (p_entry == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_LINE_CREATE; /* Should not occur. See note #1. */
|
|
goto exit;
|
|
}
|
|
|
|
str_len = p_entry->StrLen + 1; /* Length of method + length of space char. */
|
|
|
|
if (str_len > p_conn->BufLen) {
|
|
*p_err = HTTPc_ERR_TRANS_BUF_LEN_INVALID; /* Should not occur. */
|
|
goto exit;
|
|
}
|
|
|
|
if (str_len > buf_len) { /* HTTP buf space not enough, return to Tx data. */
|
|
p_conn->TxDataLen += (p_buf_wr_start - p_buf);
|
|
p_conn->TxDataPtr = p_conn->TxBufPtr;
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_LINE_METHOD;
|
|
*p_err = HTTPc_ERR_TRANS_TX_BUF_FULL;
|
|
goto exit;
|
|
}
|
|
/* Write Request method to buffer. */
|
|
p_buf_wr_end = Str_Copy_N(p_buf_wr_start, p_entry->StrPtr, p_entry->StrLen);
|
|
if (p_buf_wr_end == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_LINE_CREATE;
|
|
goto exit;
|
|
}
|
|
p_buf_wr_end += p_entry->StrLen;
|
|
|
|
*p_buf_wr_end = ASCII_CHAR_SPACE; /* Write space character to buffer. */
|
|
p_buf_wr_end++;
|
|
|
|
buf_len -= (p_buf_wr_end - p_buf_wr_start); /* Update buffer length remaining. */
|
|
p_buf_wr_start = p_buf_wr_end;
|
|
/* 'break' intentionally omitted. */
|
|
|
|
|
|
case HTTPc_CONN_STATE_REQ_LINE_URI:
|
|
/* --------------- PREPARE REQ LINE URI---------------- */
|
|
str_len = Str_Len_N(p_req->ResourcePathPtr, p_req->ResourcePathLen);
|
|
|
|
if (str_len <= buf_len) {
|
|
/* IF HTTP buf space is enough, copy Resource path. */
|
|
p_buf_wr_end = Str_Copy_N(p_buf_wr_start, p_req->ResourcePathPtr, str_len);
|
|
if (p_buf_wr_end == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_LINE_CREATE;
|
|
goto exit;
|
|
}
|
|
p_buf_wr_end += str_len;
|
|
|
|
buf_len -= (p_buf_wr_end - p_buf_wr_start); /* Update buffer length remaining. */
|
|
p_buf_wr_start = p_buf_wr_end;
|
|
|
|
} else { /* ELSE (buffer space is not enough) ... */
|
|
switch (p_conn->State) {
|
|
case HTTPc_CONN_STATE_REQ_LINE_METHOD: /* Start by exit function to allow remaining data in ...*/
|
|
/* ... buffer to be transmit. */
|
|
p_conn->TxDataLen += (p_buf_wr_end - p_buf);
|
|
p_conn->TxDataPtr = p_conn->TxBufPtr;
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_LINE_URI;
|
|
break;
|
|
|
|
|
|
case HTTPc_CONN_STATE_REQ_LINE_URI: /* Second time around, set TxDataPtr to point to ... */
|
|
/* ... Resource Path ptr. */
|
|
p_conn->TxDataLen = str_len;
|
|
p_conn->TxDataPtr = p_req->ResourcePathPtr;
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_LINE_QUERY_STR;
|
|
break;
|
|
|
|
|
|
default:
|
|
*p_err = HTTPc_ERR_CONN_INVALID_STATE;
|
|
goto exit;
|
|
}
|
|
break; /* break from upper HTTPc_CONN_STATE_REQ_LINE_URI case. */
|
|
}
|
|
/* 'break' intentionally omitted. */
|
|
|
|
|
|
case HTTPc_CONN_STATE_REQ_LINE_QUERY_STR:
|
|
*p_err = HTTPc_ERR_NONE;
|
|
/* ---------- PREPARE REQ LINE QUERY STRINGS ---------- */
|
|
#if (HTTPc_CFG_QUERY_STR_EN == DEF_ENABLED)
|
|
if (p_req->QueryStrTbl != DEF_NULL) {
|
|
/* Write String Query to buffer. */
|
|
p_buf_wr_end = HTTPcReq_QueryStrTbl(p_conn,
|
|
p_buf_wr_start,
|
|
buf_len,
|
|
p_err);
|
|
}
|
|
if (p_req->OnQueryStrTx != DEF_NULL) {
|
|
/* Write String Query to buffer. */
|
|
p_buf_wr_end = HTTPcReq_QueryStrHook(p_conn,
|
|
p_buf_wr_start,
|
|
buf_len,
|
|
p_err);
|
|
}
|
|
switch (*p_err) {
|
|
case HTTPc_ERR_NONE: /* All the Query Strings were copied to the HTTP buf. */
|
|
buf_len -= (p_buf_wr_end - p_buf_wr_start);
|
|
p_buf_wr_start = p_buf_wr_end;
|
|
break;
|
|
|
|
|
|
case HTTPc_ERR_TRANS_TX_BUF_FULL: /* HTTP buf full before all Queries were copied. */
|
|
p_conn->TxDataLen += (p_buf_wr_end - p_buf);
|
|
p_conn->TxDataPtr = p_conn->TxBufPtr;
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_LINE_QUERY_STR;
|
|
goto exit;
|
|
|
|
|
|
default:
|
|
p_conn->TxDataLen = 0;
|
|
goto exit;
|
|
}
|
|
|
|
#endif
|
|
p_conn->TxDataPtr = p_conn->TxBufPtr; /* Reset TxDataPtr to point to the HTTP buffer. */
|
|
/* 'break' intentionally omitted. */
|
|
|
|
|
|
case HTTPc_CONN_STATE_REQ_LINE_PROTO_VER:
|
|
/* -------- PREPARE REQ LINE PROTOCOL VERSION --------- */
|
|
/* Find HTTP version in dictionary. */
|
|
p_entry = HTTP_Dict_EntryGet(HTTP_Dict_ProtocolVer,
|
|
HTTP_Dict_ProtocolVerSize,
|
|
HTTP_PROTOCOL_VER_1_1);
|
|
if (p_entry == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_LINE_CREATE; /* Should not occur. See note #1. */
|
|
goto exit;
|
|
}
|
|
|
|
str_len = p_entry->StrLen + 1 + STR_CR_LF_LEN; /* total len = len of version + len of space + */
|
|
/* len of end of line. */
|
|
|
|
if (str_len > p_conn->BufLen) {
|
|
*p_err = HTTPc_ERR_TRANS_BUF_LEN_INVALID; /* See Note #5. */
|
|
goto exit;
|
|
}
|
|
|
|
if (str_len > buf_len) { /* HTTP Buf space remaining not enough. */
|
|
p_conn->TxDataLen += (p_buf_wr_start - p_buf);
|
|
p_conn->TxDataPtr = p_conn->TxBufPtr;
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_LINE_PROTO_VER;
|
|
*p_err = HTTPc_ERR_TRANS_TX_BUF_FULL;
|
|
goto exit;
|
|
}
|
|
|
|
*p_buf_wr_end = ASCII_CHAR_SPACE; /* Copy Space character. */
|
|
p_buf_wr_end++;
|
|
|
|
/* Copy HTTP Protocol version. */
|
|
p_buf_wr_end = Str_Copy_N(p_buf_wr_end, p_entry->StrPtr, p_entry->StrLen);
|
|
if (p_buf_wr_end == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_LINE_CREATE;
|
|
goto exit;
|
|
}
|
|
p_buf_wr_end += p_entry->StrLen;
|
|
|
|
/* Copy end of line CRLF. */
|
|
p_buf_wr_end = Str_Copy_N(p_buf_wr_end, STR_CR_LF, buf_len);
|
|
if (p_buf_wr_end == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_LINE_CREATE;
|
|
goto exit;
|
|
}
|
|
p_buf_wr_end += STR_CR_LF_LEN;
|
|
|
|
p_conn->TxDataLen = (p_buf_wr_end - p_buf); /* Update data length to transmit. */
|
|
p_conn->TxDataPtr = p_conn->TxBufPtr;
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_HDR_HOST; /* Set next state to prepare request headers. */
|
|
break;
|
|
|
|
|
|
default:
|
|
*p_err = HTTPc_ERR_CONN_INVALID_STATE;
|
|
goto exit;
|
|
}
|
|
|
|
*p_err = HTTPc_ERR_NONE;
|
|
|
|
|
|
exit:
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* HTTPcReq_QueryStrTbl()
|
|
*
|
|
* Description : Parse Query String table and prepare the query string to be transmitted.
|
|
*
|
|
* Argument(s) : p_conn Pointer to current HTTPc connection.
|
|
*
|
|
* p_buf Pointer to where the data must be copied in the HTTP buffer.
|
|
*
|
|
* buf_len_rem Buffer length remaining.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* HTTPc_ERR_NONE All query strings prepared and copied to buf.
|
|
* HTTPc_ERR_TRANS_BUF_LEN_INVALID HTTP buffer length is not enough big.
|
|
* HTTPc_ERR_TRANS_TX_BUF_FULL HTTP buffer is full, data must be Tx.
|
|
* HTTPc_ERR_REQ_QUERY_STR_CREATE Fatal error occurred in query preparation.
|
|
*
|
|
* Return(s) : Pointer to location after the end of the data written.
|
|
*
|
|
* Caller(s) : HTTPcReq_Line().
|
|
*
|
|
* Note(s) : (1) Since the Query Strings are passed by the App in the form of a table, the process will
|
|
* copy as much as queries possible to the HTTP buffer before returning. If not all the
|
|
* queries fit inside the buffer, the index of the table will be saved and the function
|
|
* will exit to allow transmission of data. Next time around the process will resume
|
|
* at the saved index.
|
|
*
|
|
* (2) Note that each Query (Key-Value Pair) MUST individually fit inside the HTTP buffer
|
|
* since a query is not divisible.
|
|
*********************************************************************************************************
|
|
*/
|
|
#if HTTPc_CFG_QUERY_STR_EN == DEF_ENABLED
|
|
static CPU_CHAR *HTTPcReq_QueryStrTbl(HTTPc_CONN *p_conn,
|
|
CPU_CHAR *p_buf,
|
|
CPU_INT16U buf_len_rem,
|
|
HTTPc_ERR *p_err)
|
|
{
|
|
HTTPc_REQ *p_req;
|
|
HTTPc_KEY_VAL *p_kvp;
|
|
CPU_CHAR *p_buf_wr;
|
|
CPU_SIZE_T str_len_key;
|
|
CPU_SIZE_T str_len_val;
|
|
CPU_SIZE_T space_req;
|
|
CPU_BOOLEAN first;
|
|
CPU_BOOLEAN url_encode;
|
|
CPU_INT16U encode_nbr;
|
|
CPU_INT08U i;
|
|
|
|
|
|
p_req = p_conn->ReqListHeadPtr;
|
|
/* ------------- PARSE QUERY STRING TABLE ------------- */
|
|
p_buf_wr = p_buf;
|
|
p_kvp = &p_req->QueryStrTbl[0];
|
|
first = DEF_BIT_IS_CLR(p_conn->ReqFlags, HTTPc_FLAG_REQ_LINE_QUERY_STR_BEGIN);
|
|
|
|
for (i = p_conn->ReqQueryStrTxIx; i < p_req->QueryStrNbr; i++) {
|
|
|
|
if (first == DEF_YES) { /* Query String start with a ? after the URI. */
|
|
*p_buf_wr = ASCII_CHAR_QUESTION_MARK;
|
|
p_buf_wr++;
|
|
buf_len_rem--;
|
|
DEF_BIT_SET(p_conn->ReqFlags, HTTPc_FLAG_REQ_LINE_QUERY_STR_BEGIN);
|
|
first = DEF_NO;
|
|
}
|
|
|
|
/* Calculate total length required by one key-val pair. */
|
|
space_req = 0;
|
|
str_len_key = Str_Len_N(p_kvp->KeyPtr, p_kvp->KeyLen);
|
|
encode_nbr = HTTP_URL_CharEncodeNbr(p_kvp->KeyPtr, str_len_key);
|
|
space_req += (str_len_key + encode_nbr * HTTP_URL_ENCODING_JUMP);
|
|
|
|
if (p_kvp->ValPtr != DEF_NULL) {
|
|
str_len_val = Str_Len_N(p_kvp->ValPtr, p_kvp->ValLen);
|
|
encode_nbr = HTTP_URL_CharEncodeNbr(p_kvp->ValPtr, str_len_val);
|
|
space_req += (str_len_val + encode_nbr * HTTP_URL_ENCODING_JUMP);
|
|
|
|
space_req += 1; /* Add length of "=" character. */
|
|
}
|
|
|
|
space_req += 1; /* Add length of "&" character. */
|
|
|
|
|
|
if (space_req > p_conn->BufLen) { /* Return error if HTTP buf is to small for 1 pair. */
|
|
*p_err = HTTPc_ERR_TRANS_BUF_LEN_INVALID;
|
|
goto exit;
|
|
}
|
|
|
|
if (space_req > buf_len_rem) { /* HTTP buf remaining space not enough. */
|
|
p_conn->ReqQueryStrTxIx = i; /* Save table index to resume at right place. */
|
|
*p_err = HTTPc_ERR_TRANS_TX_BUF_FULL;
|
|
goto exit; /* Exit to allow data to be transmitted. */
|
|
}
|
|
|
|
url_encode = HTTP_URL_EncodeStr(p_kvp->KeyPtr, /* URL-encode and copy the query key. */
|
|
p_buf_wr,
|
|
&str_len_key,
|
|
buf_len_rem);
|
|
if (url_encode == DEF_FAIL) {
|
|
p_buf_wr = p_buf;
|
|
*p_err = HTTPc_ERR_REQ_QUERY_STR_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
p_buf_wr += str_len_key;
|
|
buf_len_rem -= str_len_key;
|
|
|
|
if (p_kvp->ValPtr != DEF_NULL) {
|
|
*p_buf_wr = ASCII_CHAR_EQUALS_SIGN; /* Copy "=" character between key and value. */
|
|
p_buf_wr++;
|
|
buf_len_rem--;
|
|
|
|
url_encode = HTTP_URL_EncodeStr(p_kvp->ValPtr, /* URL-encode and copy the query value. */
|
|
p_buf_wr,
|
|
&str_len_val,
|
|
buf_len_rem);
|
|
if (url_encode == DEF_FAIL) {
|
|
p_buf_wr = p_buf;
|
|
*p_err = HTTPc_ERR_REQ_QUERY_STR_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
p_buf_wr += str_len_val;
|
|
buf_len_rem -= str_len_val;
|
|
}
|
|
|
|
if (i < (p_req->QueryStrNbr - 1)) {
|
|
*p_buf_wr = ASCII_CHAR_AMPERSAND; /* Copy "&" character if query pair is not the last. */
|
|
p_buf_wr++;
|
|
buf_len_rem--;
|
|
} else {
|
|
p_conn->ReqQueryStrTxIx = 0u;
|
|
}
|
|
|
|
p_buf = p_buf_wr;
|
|
|
|
p_kvp++;
|
|
}
|
|
|
|
*p_err = HTTPc_ERR_NONE;
|
|
|
|
|
|
exit:
|
|
return (p_buf_wr);
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* HTTPcReq_QueryStrHook()
|
|
*
|
|
* Description : (1) Call hook function to recover each part of the query string.
|
|
* (2) Prepare the query string to be transmitted.
|
|
*
|
|
*
|
|
* Argument(s) : p_conn Pointer to current HTTPc Connection object.
|
|
*
|
|
* p_buf Pointer to where the data must be copied in the HTTP buffer.
|
|
*
|
|
* buf_len_rem Buffer length remaining.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* HTTPc_ERR_NONE All query strings prepared and copied to buf.
|
|
* HTTPc_ERR_TRANS_BUF_LEN_INVALID HTTP buffer length is not enough big.
|
|
* HTTPc_ERR_TRANS_TX_BUF_FULL HTTP buffer is full, data must be Tx.
|
|
* HTTPc_ERR_REQ_QUERY_STR_CREATE Fatal error occurred in query preparation.
|
|
*
|
|
* Return(s) : Pointer to location after the end of the data written.
|
|
*
|
|
* Caller(s) : HTTPcReq_Line().
|
|
*
|
|
* Note(s) : (1) Since the Query Strings are passed by the App hook function, the process will
|
|
* copy as much as queries possible to the HTTP buffer before returning. If not all the
|
|
* queries fit inside the buffer, a pointer to the last key-value pair will be saved and
|
|
* the function will exit to allow transmission of data. Next time around the process will resume
|
|
* at the saved pointer before calling the hook.
|
|
*
|
|
* (2) Note that each Query (Key-Value Pair) MUST individually fit inside the HTTP buffer
|
|
* since a query is not divisible.
|
|
*********************************************************************************************************
|
|
*/
|
|
#if HTTPc_CFG_QUERY_STR_EN == DEF_ENABLED
|
|
static CPU_CHAR *HTTPcReq_QueryStrHook(HTTPc_CONN *p_conn,
|
|
CPU_CHAR *p_buf,
|
|
CPU_INT16U buf_len_rem,
|
|
HTTPc_ERR *p_err)
|
|
{
|
|
HTTPc_CONN_OBJ *p_conn_const;
|
|
HTTPc_REQ *p_req;
|
|
HTTPc_REQ_OBJ *p_req_const;
|
|
HTTPc_KEY_VAL *p_kvp;
|
|
CPU_CHAR *p_buf_wr;
|
|
CPU_SIZE_T str_len_key;
|
|
CPU_SIZE_T str_len_val;
|
|
CPU_SIZE_T space_req;
|
|
CPU_BOOLEAN first;
|
|
CPU_BOOLEAN done;
|
|
CPU_BOOLEAN url_encode;
|
|
CPU_INT16U encode_nbr;
|
|
|
|
|
|
p_conn_const = (HTTPc_CONN_OBJ *)p_conn;
|
|
|
|
p_req = p_conn->ReqListHeadPtr;
|
|
p_req_const = (HTTPc_REQ_OBJ *)p_req;
|
|
|
|
p_buf_wr = p_buf;
|
|
done = DEF_NO;
|
|
first = DEF_BIT_IS_CLR(p_conn->ReqFlags, HTTPc_FLAG_REQ_LINE_QUERY_STR_BEGIN);
|
|
|
|
while (done == DEF_NO) {
|
|
|
|
if (p_conn->ReqQueryStrTempPtr != DEF_NULL) {
|
|
p_kvp = p_conn->ReqQueryStrTempPtr;
|
|
done = DEF_BIT_IS_SET(p_conn->ReqFlags, HTTPc_FLAG_REQ_LINE_QUERY_STR_DONE);
|
|
p_conn->ReqQueryStrTempPtr = DEF_NULL;
|
|
} else {
|
|
done = p_req->OnQueryStrTx(p_conn_const, p_req_const, &p_kvp);
|
|
if (p_kvp == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_QUERY_STR_INVALID;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
if (first == DEF_YES) { /* Query String start with a ? after the URI. */
|
|
*p_buf_wr = ASCII_CHAR_QUESTION_MARK;
|
|
p_buf_wr++;
|
|
buf_len_rem--;
|
|
DEF_BIT_SET(p_conn->ReqFlags, HTTPc_FLAG_REQ_LINE_QUERY_STR_BEGIN);
|
|
first = DEF_NO;
|
|
}
|
|
|
|
/* Calculate total length required by one key-val pair. */
|
|
space_req = 0;
|
|
str_len_key = Str_Len_N(p_kvp->KeyPtr, p_kvp->KeyLen);
|
|
encode_nbr = HTTP_URL_CharEncodeNbr(p_kvp->KeyPtr, str_len_key);
|
|
space_req += (str_len_key + encode_nbr * HTTP_URL_ENCODING_JUMP);
|
|
|
|
if (p_kvp->ValPtr != DEF_NULL) {
|
|
str_len_val = Str_Len_N(p_kvp->ValPtr, p_kvp->ValLen);
|
|
encode_nbr = HTTP_URL_CharEncodeNbr(p_kvp->ValPtr, str_len_val);
|
|
space_req += (str_len_val + encode_nbr * HTTP_URL_ENCODING_JUMP);
|
|
|
|
space_req += 1; /* Add length of "=" character. */
|
|
}
|
|
|
|
space_req += 1; /* Add length of "&" character. */
|
|
|
|
if (space_req > p_conn->BufLen) { /* Return error if HTTP buf is to small for 1 pair. */
|
|
*p_err = HTTPc_ERR_TRANS_BUF_LEN_INVALID;
|
|
goto exit;
|
|
}
|
|
|
|
if (space_req > buf_len_rem) { /* HTTP buf remaining space not enough. */
|
|
p_conn->ReqQueryStrTempPtr = p_kvp;
|
|
if (done == DEF_YES) {
|
|
DEF_BIT_SET(p_conn->ReqFlags, HTTPc_FLAG_REQ_LINE_QUERY_STR_DONE);
|
|
}
|
|
*p_err = HTTPc_ERR_TRANS_TX_BUF_FULL;
|
|
goto exit; /* Exit to allow data to be transmitted. */
|
|
}
|
|
|
|
url_encode = HTTP_URL_EncodeStr(p_kvp->KeyPtr, /* URL-encode and copy the query key. */
|
|
p_buf_wr,
|
|
&str_len_key,
|
|
buf_len_rem);
|
|
if (url_encode == DEF_FAIL) {
|
|
p_buf_wr = p_buf;
|
|
*p_err = HTTPc_ERR_REQ_QUERY_STR_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
p_buf_wr += str_len_key;
|
|
buf_len_rem -= str_len_key;
|
|
|
|
if (p_kvp->ValPtr != DEF_NULL) {
|
|
*p_buf_wr = ASCII_CHAR_EQUALS_SIGN; /* Copy "=" character between key and value. */
|
|
p_buf_wr++;
|
|
buf_len_rem--;
|
|
|
|
url_encode = HTTP_URL_EncodeStr(p_kvp->ValPtr, /* URL-encode and copy the query value. */
|
|
p_buf_wr,
|
|
&str_len_val,
|
|
buf_len_rem);
|
|
if (url_encode == DEF_FAIL) {
|
|
p_buf_wr = p_buf;
|
|
*p_err = HTTPc_ERR_REQ_QUERY_STR_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
p_buf_wr += str_len_val;
|
|
buf_len_rem -= str_len_val;
|
|
}
|
|
|
|
if (done == DEF_NO) {
|
|
*p_buf_wr = ASCII_CHAR_AMPERSAND; /* Copy "&" character if query pair is not the last. */
|
|
p_buf_wr++;
|
|
buf_len_rem--;
|
|
}
|
|
|
|
p_buf = p_buf_wr;
|
|
}
|
|
|
|
*p_err = HTTPc_ERR_NONE;
|
|
|
|
|
|
exit:
|
|
return (p_buf_wr);
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* HTTPcReq_Hdr()
|
|
*
|
|
* Description : (1) Prepare and Copy HTTP Request Headers to HTTP Tx buffer.
|
|
*
|
|
* (a) Host, Connection, Content-Type, Content-Length and Transfer-Encoding headers
|
|
* are processed by the HTTPc core.
|
|
*
|
|
* (b) Extra Headers table given by application is parse to add headers to request.
|
|
*
|
|
*
|
|
* 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 All headers copy to buffer successfully.
|
|
* HTTPc_ERR_REQ_HDR_CREATE Fatal error while creating header.
|
|
* HTTPc_ERR_TRANS_BUF_LEN_INVALID HTTP buffer length is not enough big.
|
|
* HTTPc_ERR_TRANS_TX_BUF_FULL HTTP buffer is full, data must be Tx.
|
|
* HTTPc_ERR_CONN_INVALID_STATE Invalid connection state.
|
|
*
|
|
* ------------ RETURNED BY HTTPcReq_HdrCopyToBuf() ------------
|
|
* See HTTPcReq_HdrCopyToBuf() for additional return error codes.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Caller(s) : HTTPcReq().
|
|
*
|
|
* Note(s) : (2) HTTP Header parameters previously validate in API function HTTPc_SetReqExtHdr()
|
|
* and in HTTPcReq_Prepare().
|
|
*
|
|
* (3) The Request headers processing is design as a state machine with 4 different states:
|
|
* HTTPc_CONN_STATE_REQ_HDR_HOST
|
|
* HTTPc_CONN_STATE_REQ_HDR_CONN
|
|
* HTTPc_CONN_STATE_REQ_HDR_CONTENT_TYPE
|
|
* HTTPc_CONN_STATE_REQ_HDR_TRANSFER_ENCODE
|
|
* HTTPc_CONN_STATE_REQ_HDR_CONTENT_LEN
|
|
* HTTPc_CONN_STATE_REQ_HDR_EXT
|
|
*
|
|
* (4) The data length of each state MUST be smaller than the configured HTTPc buffer length.
|
|
* Else the process is aborted and the err code HTTPc_ERR_TRANS_BUF_LEN_INVALID is returned.
|
|
* The buffer length MUST be reconfigured and increased.
|
|
*
|
|
* (5) The function will not return until all the request headers has been copied to the HTTP
|
|
* buffer or if the buffer is full before the end of the header processing. In that case,
|
|
* the state is saved and the function will exit to allow the data to be transmit.
|
|
* Next time around the process will resume at the saved state.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void HTTPcReq_Hdr(HTTPc_CONN *p_conn,
|
|
HTTPc_ERR *p_err)
|
|
{
|
|
HTTPc_REQ *p_req;
|
|
HTTP_DICT *p_entry;
|
|
CPU_CHAR *p_str;
|
|
CPU_CHAR *p_buf;
|
|
CPU_CHAR *p_buf_wr;
|
|
CPU_CHAR content_len_str[DEF_INT_32U_NBR_DIG_MAX + 1];
|
|
CPU_SIZE_T buf_len;
|
|
CPU_SIZE_T len;
|
|
CPU_BOOLEAN flag_en;
|
|
CPU_INT32U key;
|
|
#ifdef HTTPc_WEBSOCK_MODULE_EN
|
|
HTTPc_WEBSOCK_REQ *p_ws_req;
|
|
#endif
|
|
|
|
|
|
p_req = p_conn->ReqListHeadPtr;
|
|
|
|
p_buf = p_conn->TxBufPtr + p_conn->TxDataLen;
|
|
buf_len = p_conn->BufLen - p_conn->TxDataLen;
|
|
p_buf_wr = p_buf;
|
|
|
|
/* --------------- ADD REQUIRED HEADERS --------------- */
|
|
switch (p_conn->State) {
|
|
case HTTPc_CONN_STATE_REQ_HDR_HOST:
|
|
/* --------------- COPY HOST HDR FIELD ---------------- */
|
|
flag_en = DEF_BIT_IS_SET(p_req->HdrFlags, HTTPc_FLAG_REQ_HDR_HOST_ADD);
|
|
if (flag_en == DEF_YES) {
|
|
if ((p_conn->ServerPort == HTTP_DFLT_PORT_NBR) ||
|
|
(p_conn->ServerPort == HTTP_DFLT_PORT_NBR_SECURE)) {
|
|
p_str = HTTPcReq_HdrCopyToBuf(p_buf_wr,
|
|
p_conn->BufLen,
|
|
buf_len,
|
|
HTTP_HDR_FIELD_HOST,
|
|
p_conn->HostNamePtr,
|
|
p_conn->HostNameLen,
|
|
DEF_YES,
|
|
p_err);
|
|
if (p_str == DEF_NULL) {
|
|
goto exit;
|
|
}
|
|
|
|
buf_len -= (p_str - p_buf_wr);
|
|
p_buf_wr = p_str;
|
|
|
|
} else {
|
|
/* If not http dflt port, add the port nbr to host hdr. */
|
|
p_str = HTTPcReq_HdrCopyToBuf(p_buf_wr,
|
|
p_conn->BufLen,
|
|
buf_len,
|
|
HTTP_HDR_FIELD_HOST,
|
|
p_conn->HostNamePtr,
|
|
p_conn->HostNameLen,
|
|
DEF_NO,
|
|
p_err);
|
|
if (p_str == DEF_NULL) {
|
|
goto exit;
|
|
}
|
|
|
|
buf_len -= (p_str - p_buf_wr);
|
|
p_buf_wr = p_str;
|
|
|
|
if (buf_len >= 1) {
|
|
*p_str = ASCII_CHAR_COLON;
|
|
p_str++;
|
|
} else {
|
|
*p_err = HTTPc_ERR_REQ_HDR_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
buf_len -= (p_str - p_buf_wr);
|
|
p_buf_wr = p_str;
|
|
|
|
p_str = Str_FmtNbr_Int32U(p_conn->ServerPort,
|
|
5u,
|
|
DEF_NBR_BASE_DEC,
|
|
DEF_NULL,
|
|
DEF_NO,
|
|
DEF_YES,
|
|
p_buf_wr);
|
|
if (p_str == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_HDR_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
p_str += Str_Len(p_str);
|
|
|
|
buf_len -= (p_str - p_buf_wr);
|
|
p_buf_wr = p_str;
|
|
|
|
p_str = Str_Copy_N(p_str, STR_CR_LF, buf_len);
|
|
if (p_str == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_HDR_CREATE;
|
|
goto exit;
|
|
}
|
|
p_str += STR_CR_LF_LEN;
|
|
buf_len -= p_str - p_buf_wr;
|
|
p_buf_wr = p_str;
|
|
}
|
|
}
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_HDR_CONN;
|
|
/* 'break' intentionally omitted. */
|
|
|
|
|
|
case HTTPc_CONN_STATE_REQ_HDR_CONN:
|
|
/* ------------- COPY CONNECTION HDR FIELD ------------- */
|
|
key = HTTP_DICT_KEY_INVALID;
|
|
flag_en = DEF_BIT_IS_SET(p_req->HdrFlags, HTTPc_FLAG_REQ_HDR_CONNECTION_ADD);
|
|
if (flag_en == DEF_YES) {
|
|
/* Check the value for the connection hdr field. */
|
|
flag_en = DEF_BIT_IS_SET(p_conn->Flags, HTTPc_FLAG_CONN_TO_CLOSE);
|
|
if (flag_en == DEF_YES) {
|
|
key = HTTP_HDR_FIELD_CONN_CLOSE;
|
|
} else {
|
|
#ifdef HTTPc_WEBSOCK_MODULE_EN
|
|
flag_en = DEF_BIT_IS_SET(p_req->Flags, HTTPc_FLAG_REQ_UPGRADE_WEBSOCKET);
|
|
if (flag_en == DEF_YES) {
|
|
key = HTTP_HDR_FIELD_CONN_UPGRADE;
|
|
}
|
|
#endif
|
|
}
|
|
p_entry = HTTP_Dict_EntryGet(HTTP_Dict_HdrFieldConnVal,
|
|
HTTP_Dict_HdrFieldConnValSize,
|
|
key);
|
|
if (p_entry == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_HDR_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
p_str = HTTPcReq_HdrCopyToBuf(p_buf_wr,
|
|
p_conn->BufLen,
|
|
buf_len,
|
|
HTTP_HDR_FIELD_CONN,
|
|
p_entry->StrPtr,
|
|
p_entry->StrLen,
|
|
DEF_YES,
|
|
p_err);
|
|
if (p_str == DEF_NULL) {
|
|
goto exit;
|
|
}
|
|
|
|
buf_len -= (p_str - p_buf_wr);
|
|
p_buf_wr = p_str;
|
|
}
|
|
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_HDR_CONTENT_TYPE;
|
|
/* 'break' intentionally omitted. */
|
|
|
|
|
|
case HTTPc_CONN_STATE_REQ_HDR_CONTENT_TYPE:
|
|
/* ----------- COPY CONTENT-TYPE HDR FIELD ------------ */
|
|
flag_en = DEF_BIT_IS_SET(p_req->HdrFlags, HTTPc_FLAG_REQ_HDR_CONTENT_TYPE_ADD);
|
|
if (flag_en == DEF_YES) {
|
|
p_entry = HTTP_Dict_EntryGet(HTTP_Dict_ContentType,
|
|
HTTP_Dict_ContentTypeSize,
|
|
p_req->ContentType);
|
|
if (p_entry == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_HDR_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
if (p_req->ContentType != HTTP_CONTENT_TYPE_MULTIPART_FORM) {
|
|
p_str = HTTPcReq_HdrCopyToBuf(p_buf_wr,
|
|
p_conn->BufLen,
|
|
buf_len,
|
|
HTTP_HDR_FIELD_CONTENT_TYPE,
|
|
p_entry->StrPtr,
|
|
p_entry->StrLen,
|
|
DEF_YES,
|
|
p_err);
|
|
if (p_str == DEF_NULL) {
|
|
goto exit;
|
|
}
|
|
|
|
} else {
|
|
|
|
len = HTTP_STR_HDR_FIELD_CONTENT_TYPE_LEN +
|
|
2 +
|
|
p_entry->StrLen +
|
|
2 +
|
|
HTTP_STR_MULTIPART_BOUNDARY_LEN +
|
|
1 +
|
|
HTTPc_STR_BOUNDARY_LEN +
|
|
STR_CR_LF_LEN;
|
|
|
|
if (len > p_conn->BufLen) {
|
|
*p_err = HTTPc_ERR_TRANS_BUF_LEN_INVALID;
|
|
goto exit;
|
|
}
|
|
|
|
if (len > buf_len) {
|
|
*p_err = HTTPc_ERR_TRANS_TX_BUF_FULL;
|
|
goto exit;
|
|
}
|
|
|
|
p_str = HTTPcReq_HdrCopyToBuf(p_buf_wr,
|
|
p_conn->BufLen,
|
|
buf_len,
|
|
HTTP_HDR_FIELD_CONTENT_TYPE,
|
|
p_entry->StrPtr,
|
|
p_entry->StrLen,
|
|
DEF_NO,
|
|
p_err);
|
|
if (p_str == DEF_NULL) {
|
|
goto exit;
|
|
}
|
|
|
|
buf_len -= (p_str - p_buf_wr);
|
|
p_buf_wr = p_str;
|
|
|
|
*p_str = ASCII_CHAR_SEMICOLON;
|
|
p_str++;
|
|
*p_str = ASCII_CHAR_SPACE;
|
|
p_str++;
|
|
|
|
p_str = Str_Copy_N(p_str, HTTP_STR_MULTIPART_BOUNDARY, HTTP_STR_MULTIPART_BOUNDARY_LEN);
|
|
if (p_str == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_HDR_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
p_str += HTTP_STR_MULTIPART_BOUNDARY_LEN;
|
|
*p_str = ASCII_CHAR_EQUALS_SIGN;
|
|
p_str++;
|
|
|
|
p_str = Str_Copy_N(p_str, HTTPc_STR_BOUNDARY, HTTPc_STR_BOUNDARY_LEN);
|
|
if (p_str == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_HDR_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
p_str += HTTPc_STR_BOUNDARY_LEN;
|
|
|
|
p_str = Str_Copy_N(p_str, STR_CR_LF, STR_CR_LF_LEN);
|
|
if (p_str == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_HDR_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
p_str += STR_CR_LF_LEN;
|
|
}
|
|
|
|
buf_len -= (p_str - p_buf_wr);
|
|
p_buf_wr = p_str;
|
|
}
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_HDR_TRANSFER_ENCODE;
|
|
/* 'break' intentionally omitted. */
|
|
|
|
|
|
case HTTPc_CONN_STATE_REQ_HDR_TRANSFER_ENCODE:
|
|
/* --------- COPY TRANSFER-ENCODING HDR FIELD --------- */
|
|
flag_en = DEF_BIT_IS_SET(p_req->HdrFlags, HTTPc_FLAG_REQ_HDR_TRANSFER_ENCODE_ADD);
|
|
if (flag_en == DEF_YES) {
|
|
p_entry = HTTP_Dict_EntryGet(HTTP_Dict_HdrFieldTransferTypeVal,
|
|
HTTP_Dict_HdrFieldTransferTypeValSize,
|
|
HTTP_HDR_FIELD_TRANSFER_TYPE_CHUNKED);
|
|
if (p_entry == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_HDR_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
p_str = HTTPcReq_HdrCopyToBuf(p_buf_wr,
|
|
p_conn->BufLen,
|
|
buf_len,
|
|
HTTP_HDR_FIELD_TRANSFER_ENCODING,
|
|
p_entry->StrPtr,
|
|
p_entry->StrLen,
|
|
DEF_YES,
|
|
p_err);
|
|
if (p_str == DEF_NULL) {
|
|
goto exit;
|
|
}
|
|
|
|
buf_len -= (p_str - p_buf_wr);
|
|
p_buf_wr = p_str;
|
|
}
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_HDR_CONTENT_LEN;
|
|
/* 'break' intentionally omitted. */
|
|
|
|
|
|
case HTTPc_CONN_STATE_REQ_HDR_CONTENT_LEN:
|
|
/* ---------- COPY CONTENT-LENGTH HDR FIELD ----------- */
|
|
flag_en = DEF_BIT_IS_SET(p_req->HdrFlags, HTTPc_FLAG_REQ_HDR_CONTENT_LENGTH_ADD);
|
|
if (flag_en == DEF_YES) {
|
|
|
|
p_str = Str_FmtNbr_Int32U(p_req->ContentLen,
|
|
DEF_INT_32U_NBR_DIG_MAX,
|
|
DEF_NBR_BASE_DEC,
|
|
'\0',
|
|
DEF_NO,
|
|
DEF_YES,
|
|
content_len_str);
|
|
if (p_str == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_HDR_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
len = Str_Len_N(p_str, (DEF_INT_32U_NBR_DIG_MAX + 1));
|
|
|
|
p_str = HTTPcReq_HdrCopyToBuf(p_buf_wr,
|
|
p_conn->BufLen,
|
|
buf_len,
|
|
HTTP_HDR_FIELD_CONTENT_LEN,
|
|
p_str,
|
|
len,
|
|
DEF_YES,
|
|
p_err);
|
|
if (p_str == DEF_NULL) {
|
|
goto exit;
|
|
}
|
|
|
|
buf_len -= (p_str - p_buf_wr);
|
|
p_buf_wr = p_str;
|
|
}
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_HDR_UPGRADE;
|
|
/* 'break' intentionally omitted. */
|
|
case HTTPc_CONN_STATE_REQ_HDR_UPGRADE:
|
|
|
|
#ifdef HTTPc_WEBSOCK_MODULE_EN
|
|
flag_en = DEF_BIT_IS_SET(p_req->HdrFlags, HTTPc_FLAG_REQ_HDR_UPGRADE_ADD);
|
|
if (flag_en == DEF_YES) {
|
|
|
|
p_entry = HTTP_Dict_EntryGet(HTTP_Dict_HdrFieldUpgradeVal,
|
|
HTTP_Dict_HdrFieldUpgradeValSize,
|
|
HTTP_HDR_FIELD_UPGRADE_WEBSOCKET);
|
|
if (p_entry == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_HDR_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
p_str = HTTPcReq_HdrCopyToBuf(p_buf_wr,
|
|
p_conn->BufLen,
|
|
buf_len,
|
|
HTTP_HDR_FIELD_UPGRADE,
|
|
p_entry->StrPtr,
|
|
p_entry->StrLen,
|
|
DEF_YES,
|
|
p_err);
|
|
if (p_str == DEF_NULL) {
|
|
goto exit;
|
|
}
|
|
|
|
buf_len -= (p_str - p_buf_wr);
|
|
p_buf_wr = p_str;
|
|
}
|
|
#endif
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_HDR_WEBSOCKET;
|
|
/* 'break' intentionally omitted. */
|
|
|
|
case HTTPc_CONN_STATE_REQ_HDR_WEBSOCKET:
|
|
#ifdef HTTPc_WEBSOCK_MODULE_EN
|
|
flag_en = DEF_BIT_IS_SET(p_req->HdrFlags, HTTPc_FLAG_REQ_HDR_UPGRADE_ADD);
|
|
if (flag_en == DEF_YES) {
|
|
|
|
p_ws_req = p_req->WebSockPtr;
|
|
|
|
p_str = HTTPcReq_HdrCopyToBuf(p_buf_wr,
|
|
p_conn->BufLen,
|
|
buf_len,
|
|
HTTP_HDR_FIELD_WEBSOCKET_KEY,
|
|
p_ws_req->Key,
|
|
HTTPc_WEBSOCK_KEY_ENCODED_LEN - 1,
|
|
DEF_YES,
|
|
p_err);
|
|
if (p_str == DEF_NULL) {
|
|
goto exit;
|
|
}
|
|
|
|
buf_len -= (p_str - p_buf_wr);
|
|
p_buf_wr = p_str;
|
|
|
|
p_str = HTTPcReq_HdrCopyToBuf(p_buf_wr,
|
|
p_conn->BufLen,
|
|
buf_len,
|
|
HTTP_HDR_FIELD_WEBSOCKET_VERSION,
|
|
HTTPc_WEBSOCK_PROTOCOL_VERSION_13_STR,
|
|
HTTPc_WEBSOCK_PROTOCOL_VERSION_13_STR_LEN,
|
|
DEF_YES,
|
|
p_err);
|
|
if (p_str == DEF_NULL) {
|
|
goto exit;
|
|
}
|
|
|
|
buf_len -= (p_str - p_buf_wr);
|
|
p_buf_wr = p_str;
|
|
|
|
}
|
|
#endif
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_HDR_EXT;
|
|
/* 'break' intentionally omitted. */
|
|
case HTTPc_CONN_STATE_REQ_HDR_EXT:
|
|
/* -------------- COPY EXTRA HDR FIELDS --------------- */
|
|
#if (HTTPc_CFG_HDR_TX_EN == DEF_ENABLED)
|
|
if (p_req->HdrTbl != DEF_NULL) {
|
|
p_buf_wr = HTTPcReq_HdrExtTbl(p_conn, p_buf_wr, buf_len, p_err);
|
|
if (*p_err != HTTPc_ERR_NONE) {
|
|
goto exit;
|
|
}
|
|
}
|
|
if (p_req->OnHdrTx != DEF_NULL) {
|
|
p_buf_wr = HTTPcReq_HdrExtHook(p_conn, p_buf_wr, buf_len, p_err);
|
|
if (*p_err != HTTPc_ERR_NONE) {
|
|
goto exit;
|
|
}
|
|
}
|
|
#endif
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_HDR_LAST;
|
|
/* 'break' intentionally omitted. */
|
|
|
|
|
|
case HTTPc_CONN_STATE_REQ_HDR_LAST:
|
|
/* ------------- WRITE CRLF AFTER HEADERS ------------- */
|
|
if (buf_len < STR_CR_LF_LEN) {
|
|
*p_err = HTTPc_ERR_TRANS_TX_BUF_FULL;
|
|
goto exit;
|
|
}
|
|
|
|
p_str = Str_Copy_N(p_buf_wr, STR_CR_LF, buf_len);
|
|
if (p_str == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_HDR_CREATE;
|
|
goto exit;
|
|
}
|
|
p_buf_wr += STR_CR_LF_LEN;
|
|
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_BODY;
|
|
break;
|
|
|
|
|
|
default:
|
|
*p_err = HTTPc_ERR_CONN_INVALID_STATE;
|
|
break;
|
|
}
|
|
|
|
*p_err = HTTPc_ERR_NONE;
|
|
|
|
|
|
exit:
|
|
p_conn->TxDataLen += (p_buf_wr - p_buf); /* Update Data Length to transmit. */
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* HTTPcReq_HdrExtTbl()
|
|
*
|
|
* Description : Add Additional headers include in the table to the HTTP Request.
|
|
*
|
|
* Argument(s) : p_conn Pointer to the current HTTPc Connection.
|
|
*
|
|
* p_buf Pointer to where the data must be copied in the HTTP buffer.
|
|
*
|
|
* buf_len_rem Buffer length remaining.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* HTTPc_ERR_NONE Headers successfully added to request.
|
|
* HTTPc_ERR_TRANS_TX_BUF_FULL Buffer is full. Data must be Tx.
|
|
*
|
|
* ------------ RETURNED BY HTTPcReq_HdrCopyToBuf() ------------
|
|
* See HTTPcReq_HdrCopyToBuf() for additional return error codes.
|
|
*
|
|
*
|
|
* Return(s) : Pointer to location in buffer after the end of the data written.
|
|
*
|
|
* Caller(s) : HTTPcReq_Hdr().
|
|
*
|
|
* Note(s) : (1) Since the additional headers are passed by the App in the form of a table, the process will
|
|
* copy as much as headers possible to the HTTP buffer before returning. If not all the
|
|
* headers fit inside the buffer, the index of the table will be saved and the function
|
|
* will exit to allow transmission of data. Next time around the process will resume
|
|
* at the saved index.
|
|
*
|
|
* (2) Note that each header MUST individually fit inside the HTTP buffer
|
|
* since a header field is not divisible.
|
|
*********************************************************************************************************
|
|
*/
|
|
#if (HTTPc_CFG_HDR_TX_EN == DEF_ENABLED)
|
|
static CPU_CHAR *HTTPcReq_HdrExtTbl(HTTPc_CONN *p_conn,
|
|
CPU_CHAR *p_buf,
|
|
CPU_INT16U buf_len_rem,
|
|
HTTPc_ERR *p_err)
|
|
{
|
|
HTTPc_REQ *p_req;
|
|
HTTPc_HDR *p_hdr;
|
|
CPU_CHAR *p_str;
|
|
CPU_INT08U ix;
|
|
CPU_INT08U i;
|
|
|
|
|
|
p_req = p_conn->ReqListHeadPtr;
|
|
|
|
ix = p_conn->ReqHdrTxIx;
|
|
p_hdr = &p_req->HdrTbl[ix];
|
|
for (i = ix; i < p_req->HdrNbr; i++) {
|
|
|
|
p_str = HTTPcReq_HdrCopyToBuf(p_buf,
|
|
p_conn->BufLen,
|
|
buf_len_rem,
|
|
p_hdr->HdrField,
|
|
p_hdr->ValPtr,
|
|
p_hdr->ValLen,
|
|
DEF_YES,
|
|
p_err);
|
|
switch (*p_err) {
|
|
case HTTPc_ERR_NONE:
|
|
break;
|
|
|
|
|
|
case HTTPc_ERR_TRANS_TX_BUF_FULL:
|
|
p_conn->ReqHdrTxIx = i;
|
|
goto exit;
|
|
|
|
|
|
case HTTPc_ERR_TRANS_BUF_LEN_INVALID:
|
|
case HTTPc_ERR_REQ_HDR_CREATE:
|
|
default:
|
|
goto exit;
|
|
}
|
|
|
|
buf_len_rem -= (p_str - p_buf);
|
|
p_buf = p_str;
|
|
|
|
if (i == (p_req->HdrNbr - 1)) {
|
|
p_conn->ReqHdrTxIx = 0u;
|
|
}
|
|
|
|
p_hdr++;
|
|
}
|
|
|
|
|
|
*p_err = HTTPc_ERR_NONE;
|
|
|
|
exit:
|
|
return (p_buf);
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* HTTPcReq_HdrExtHook()
|
|
*
|
|
* Description : Call request Header hook function to add additional headers to the request.
|
|
*
|
|
* Argument(s) : p_conn Pointer to current HTTPc Connection.
|
|
*
|
|
* p_buf Pointer to where the data must be copied in the HTTP buffer.
|
|
*
|
|
* buf_len_rem Buffer length remaining.
|
|
*
|
|
* p_err Pointer to variable that will receive the return error code from this function :
|
|
*
|
|
* HTTPc_ERR_NONE Headers successfully added to request.
|
|
* HTTPc_ERR_TRANS_TX_BUF_FULL Buffer is full. Data must be Tx.
|
|
*
|
|
* ------------ RETURNED BY HTTPcReq_HdrCopyToBuf() ------------
|
|
* See HTTPcReq_HdrCopyToBuf() for additional return error codes.
|
|
*
|
|
* Return(s) : Pointer to location in buffer after the end of the data written.
|
|
*
|
|
* Caller(s) : HTTPcReq_Hdr().
|
|
*
|
|
* Note(s) : (1) Since the Additional Headers are passed by the App hook function, the process will
|
|
* copy as much as headers possible to the HTTP buffer before returning. If not all the
|
|
* headers fit inside the buffer, a pointer to the header field will be saved and
|
|
* the function will exit to allow transmission of data. Next time around the process will
|
|
* resume at the saved pointer before calling the hook.
|
|
*
|
|
* (2) Note that each header MUST individually fit inside the HTTP buffer
|
|
* since a header field is not divisible.
|
|
*********************************************************************************************************
|
|
*/
|
|
#if (HTTPc_CFG_HDR_TX_EN == DEF_ENABLED)
|
|
static CPU_CHAR *HTTPcReq_HdrExtHook(HTTPc_CONN *p_conn,
|
|
CPU_CHAR *p_buf,
|
|
CPU_INT16U buf_len_rem,
|
|
HTTPc_ERR *p_err)
|
|
{
|
|
HTTPc_CONN_OBJ *p_conn_const;
|
|
HTTPc_REQ *p_req;
|
|
HTTPc_REQ_OBJ *p_req_const;
|
|
HTTPc_HDR *p_hdr;
|
|
CPU_CHAR *p_str;
|
|
CPU_BOOLEAN done;
|
|
|
|
|
|
p_conn_const = (HTTPc_CONN_OBJ *)p_conn;
|
|
|
|
p_req = p_conn->ReqListHeadPtr;
|
|
p_req_const = (HTTPc_REQ_OBJ *)p_req;
|
|
|
|
done = DEF_NO;
|
|
while (done != DEF_YES) {
|
|
|
|
if (p_conn->ReqHdrTempPtr != DEF_NULL) {
|
|
p_hdr = p_conn->ReqHdrTempPtr;
|
|
done = DEF_BIT_IS_SET(p_conn->ReqFlags, HTTPc_FLAG_REQ_HDR_DONE);
|
|
p_conn->ReqHdrTempPtr = DEF_NULL;
|
|
} else {
|
|
done = p_req->OnHdrTx(p_conn_const, p_req_const, &p_hdr);
|
|
if (p_hdr == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_HDR_INVALID;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
p_str = HTTPcReq_HdrCopyToBuf(p_buf,
|
|
p_conn->BufLen,
|
|
buf_len_rem,
|
|
p_hdr->HdrField,
|
|
p_hdr->ValPtr,
|
|
p_hdr->ValLen,
|
|
DEF_YES,
|
|
p_err);
|
|
switch (*p_err) {
|
|
case HTTPc_ERR_NONE:
|
|
break;
|
|
|
|
|
|
case HTTPc_ERR_TRANS_TX_BUF_FULL:
|
|
p_conn->ReqHdrTempPtr = p_hdr;
|
|
if (done == DEF_YES) {
|
|
DEF_BIT_SET(p_conn->ReqFlags, HTTPc_FLAG_REQ_HDR_DONE);
|
|
}
|
|
goto exit;
|
|
|
|
|
|
case HTTPc_ERR_TRANS_BUF_LEN_INVALID:
|
|
case HTTPc_ERR_REQ_HDR_CREATE:
|
|
default:
|
|
goto exit;
|
|
}
|
|
|
|
buf_len_rem -= (p_str - p_buf);
|
|
p_buf = p_str;
|
|
}
|
|
|
|
*p_err = HTTPc_ERR_NONE;
|
|
|
|
|
|
exit:
|
|
return (p_buf);
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* HTTPcReq_HdrSearch()
|
|
*
|
|
* Description : Search for a HTTP header type inside the extra header table passed by the upper application.
|
|
*
|
|
* Argument(s) : p_conn Pointer to current HTTPc Connection.
|
|
*
|
|
* hdr_field HTTP header type to search for in table.
|
|
*
|
|
* Return(s) : Pointer to HTTP header object found.
|
|
* DEF_NULL if no HTTP header found.
|
|
*
|
|
* Caller(s) : HTTPc_ReqPrepare().
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
#if (HTTPc_CFG_HDR_TX_EN == DEF_ENABLED)
|
|
static HTTPc_HDR *HTTPcReq_HdrSearch(HTTPc_CONN *p_conn,
|
|
HTTP_HDR_FIELD hdr_field)
|
|
{
|
|
HTTPc_REQ *p_req;
|
|
HTTPc_HDR *p_hdr;
|
|
CPU_BOOLEAN found;
|
|
CPU_INT08U i;
|
|
|
|
|
|
p_req = p_conn->ReqListHeadPtr;
|
|
p_hdr = p_req->HdrTbl;
|
|
|
|
if (p_hdr == DEF_NULL) {
|
|
return (DEF_NULL);
|
|
}
|
|
|
|
found = DEF_NO;
|
|
for (i = 0u; i < p_req->HdrNbr; i++) {
|
|
if (p_hdr->HdrField == hdr_field) {
|
|
found = DEF_YES;
|
|
break;
|
|
}
|
|
|
|
p_hdr++;
|
|
}
|
|
|
|
if (found == DEF_YES) {
|
|
return (p_hdr);
|
|
} else {
|
|
return (DEF_NULL);
|
|
}
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* HTTPcReq_Body()
|
|
*
|
|
* Description : Prepare and Copy/Transmit HTTP Request Body.
|
|
*
|
|
* 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 processing successful.
|
|
* HTTPc_ERR_REQ_BODY_NOT_PRESENT No body present for method that requires one.
|
|
* HTTPc_ERR_REQ_CONTENT_TYPE_INVALID Invalid Content-Type with POST method.
|
|
* HTTPc_ERR_REQ_METHOD_INVALID Invalid HTTP method.
|
|
* HTTPc_ERR_CONN_INVALID_STATE Invalid connection state.
|
|
*
|
|
* ------------ RETURNED BY HTTPcReq_BodyData() -------------
|
|
* See HTTPcReq_BodyData() for additional return error codes.
|
|
*
|
|
* ------------ RETURNED BY HTTPcReq_FormApp() -------------
|
|
* See HTTPcReq_FormApp() for additional return error codes.
|
|
*
|
|
* ------------ RETURNED BY HTTPcReq_FormMultipart() -------------
|
|
* See HTTPcReq_FormMultipart() for additional return error codes.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Caller(s) : HTTPcReq().
|
|
*
|
|
* Note(s) : None.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void HTTPcReq_Body(HTTPc_CONN *p_conn,
|
|
HTTPc_ERR *p_err)
|
|
{
|
|
HTTPc_REQ *p_req;
|
|
HTTP_METHOD method;
|
|
HTTP_CONTENT_TYPE content_type;
|
|
CPU_BOOLEAN body_present;
|
|
|
|
|
|
p_req = p_conn->ReqListHeadPtr;
|
|
method = p_req->Method;
|
|
content_type = p_req->ContentType;
|
|
|
|
body_present = DEF_BIT_IS_SET(p_req->Flags, HTTPc_FLAG_REQ_BODY_PRESENT);
|
|
|
|
switch (p_conn->State) {
|
|
case HTTPc_CONN_STATE_REQ_BODY:
|
|
switch (method) {
|
|
case HTTP_METHOD_GET:
|
|
case HTTP_METHOD_HEAD:
|
|
case HTTP_METHOD_DELETE:
|
|
case HTTP_METHOD_OPTIONS:
|
|
if (body_present == DEF_NO) {
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_END;
|
|
} else {
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_BODY_DATA;
|
|
}
|
|
break;
|
|
|
|
|
|
case HTTP_METHOD_TRACE:
|
|
case HTTP_METHOD_CONNECT:
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_END;
|
|
break;
|
|
|
|
|
|
case HTTP_METHOD_POST:
|
|
if (body_present == DEF_NO) {
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_END;
|
|
break;
|
|
}
|
|
#if (HTTPc_CFG_FORM_EN == DEF_ENABLED)
|
|
if (p_req->FormFieldTbl != DEF_NULL) {
|
|
switch (content_type) {
|
|
case HTTP_CONTENT_TYPE_APP_FORM:
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_BODY_FORM_APP;
|
|
break;
|
|
|
|
|
|
case HTTP_CONTENT_TYPE_MULTIPART_FORM:
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_BODY_FORM_MULTIPART_BOUNDARY;
|
|
break;
|
|
|
|
|
|
default:
|
|
*p_err = HTTPc_ERR_REQ_PARAM_CONTENT_TYPE_INVALID;
|
|
goto exit;
|
|
}
|
|
} else {
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_BODY_DATA;
|
|
}
|
|
#else
|
|
(void)content_type;
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_BODY_DATA;
|
|
#endif
|
|
break;
|
|
|
|
|
|
case HTTP_METHOD_PUT:
|
|
if (body_present == DEF_NO) {
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_END;
|
|
break;
|
|
}
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_BODY_DATA;
|
|
break;
|
|
|
|
|
|
case HTTP_METHOD_UNKNOWN:
|
|
default:
|
|
*p_err = HTTPc_ERR_REQ_PARAM_METHOD_INVALID;
|
|
goto exit;
|
|
}
|
|
break;
|
|
|
|
|
|
case HTTPc_CONN_STATE_REQ_BODY_DATA:
|
|
case HTTPc_CONN_STATE_REQ_BODY_DATA_CHUNK_SIZE:
|
|
case HTTPc_CONN_STATE_REQ_BODY_DATA_CHUNK_DATA:
|
|
case HTTPc_CONN_STATE_REQ_BODY_DATA_CHUNK_END:
|
|
HTTPcReq_BodyData(p_conn, p_err);
|
|
if (*p_err != HTTPc_ERR_NONE) {
|
|
goto exit;
|
|
}
|
|
break;
|
|
|
|
|
|
case HTTPc_CONN_STATE_REQ_BODY_FORM_APP:
|
|
#if (HTTPc_CFG_FORM_EN == DEF_ENABLED)
|
|
HTTPcReq_FormApp(p_conn, p_err);
|
|
if (*p_err != HTTPc_ERR_NONE) {
|
|
goto exit;
|
|
}
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_END;
|
|
break;
|
|
#else
|
|
*p_err = HTTPc_ERR_FEATURE_DIS;
|
|
goto exit;
|
|
#endif
|
|
|
|
|
|
case HTTPc_CONN_STATE_REQ_BODY_FORM_MULTIPART_BOUNDARY:
|
|
case HTTPc_CONN_STATE_REQ_BODY_FORM_MULTIPART_HDR_CONTENT_DISPO:
|
|
case HTTPc_CONN_STATE_REQ_BODY_FORM_MULTIPART_HDR_CONTENT_TYPE:
|
|
case HTTPc_CONN_STATE_REQ_BODY_FORM_MULTIPART_DATA:
|
|
case HTTPc_CONN_STATE_REQ_BODY_FORM_MULTIPART_DATA_END:
|
|
case HTTPc_CONN_STATE_REQ_BODY_FORM_MULTIPART_BOUNDARY_END:
|
|
#if (HTTPc_CFG_FORM_EN == DEF_ENABLED)
|
|
HTTPcReq_FormMultipart(p_conn, p_err);
|
|
if (*p_err != HTTPc_ERR_NONE) {
|
|
goto exit;
|
|
}
|
|
break;
|
|
#else
|
|
*p_err = HTTPc_ERR_FEATURE_DIS;
|
|
goto exit;
|
|
#endif
|
|
|
|
|
|
default:
|
|
*p_err = HTTPc_ERR_CONN_INVALID_STATE;
|
|
goto exit;
|
|
}
|
|
|
|
*p_err = HTTPc_ERR_NONE;
|
|
|
|
|
|
exit:
|
|
return;
|
|
}
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* HTTPcReq_FormApp()
|
|
*
|
|
* Description : Prepare the application type form and copy it to HTTP buffer.
|
|
*
|
|
* 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 Form created and copied to buf successfully.
|
|
* HTTPc_ERR_TRANS_BUF_LEN_INVALID HTTP buffer length is not enough big.
|
|
* HTTPc_ERR_TRANS_TX_BUF_FULL HTTP buffer is full, data must be Tx.
|
|
* HTTPc_ERR_REQ_FORM_CREATE Fatal error occurred in form creation.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Caller(s) : HTTPcReq_Body().
|
|
*
|
|
* Note(s) : (1) The application-form is created with the table form passed by the upper application.
|
|
*********************************************************************************************************
|
|
*/
|
|
#if (HTTPc_CFG_FORM_EN == DEF_ENABLED)
|
|
static void HTTPcReq_FormApp(HTTPc_CONN *p_conn,
|
|
HTTPc_ERR *p_err)
|
|
{
|
|
HTTPc_REQ *p_req;
|
|
CPU_CHAR *p_buf;
|
|
CPU_CHAR *p_buf_wr;
|
|
HTTPc_FORM_TBL_FIELD *p_form_tbl;
|
|
HTTPc_FORM_TBL_FIELD *p_tbl_entry;
|
|
HTTPc_KEY_VAL *p_form_field;
|
|
CPU_INT16U key_char_encode_nbr;
|
|
CPU_INT16U val_char_encode_nbr;
|
|
CPU_SIZE_T buf_len;
|
|
CPU_SIZE_T str_len_key;
|
|
CPU_SIZE_T str_len_val;
|
|
CPU_SIZE_T data_size = 0;
|
|
CPU_BOOLEAN url_encode;
|
|
CPU_INT16U i;
|
|
|
|
|
|
p_req = p_conn->ReqListHeadPtr;
|
|
|
|
p_buf = p_conn->TxBufPtr + p_conn->TxDataLen; /* Point to beginning of free space in Tx buffer. */
|
|
buf_len = p_conn->BufLen - p_conn->TxDataLen;
|
|
p_buf_wr = p_buf;
|
|
|
|
p_form_tbl = (HTTPc_FORM_TBL_FIELD *)p_req->FormFieldTbl;
|
|
|
|
for (i = p_conn->ReqFormDataTxIx; i < p_req->FormFieldNbr; i++) {
|
|
|
|
p_tbl_entry = &p_form_tbl[i];
|
|
|
|
p_form_field = (HTTPc_KEY_VAL *)p_tbl_entry->FieldObjPtr;
|
|
|
|
/* Calculate length of key and value without encoding. */
|
|
str_len_key = p_form_field->KeyLen;
|
|
str_len_val = p_form_field->ValLen;
|
|
|
|
/* Found number of character needing URL encoding. */
|
|
key_char_encode_nbr = HTTP_URL_CharEncodeNbr(p_form_field->KeyPtr, str_len_key);
|
|
val_char_encode_nbr = HTTP_URL_CharEncodeNbr(p_form_field->ValPtr, str_len_val);
|
|
|
|
/* Calculate total size needed for key & value encoded. */
|
|
data_size = str_len_key +
|
|
str_len_val +
|
|
HTTP_URL_ENCODING_JUMP * key_char_encode_nbr +
|
|
HTTP_URL_ENCODING_JUMP * val_char_encode_nbr +
|
|
1; /* + 1 for the "=" between key & value. */
|
|
|
|
if (i < (p_req->FormFieldNbr - 1)) {
|
|
data_size++; /* + 1 for the "&" between each key&value pair. */
|
|
}
|
|
|
|
if (data_size > p_conn->BufLen) { /* Return if error if conn buf is to small for 1 pair. */
|
|
*p_err = HTTPc_ERR_TRANS_BUF_LEN_INVALID;
|
|
goto exit;
|
|
}
|
|
|
|
if (data_size > buf_len) { /* Return if no more space in buf. Need to Tx. */
|
|
p_conn->ReqFormDataTxIx = i; /* Save the tbl index to start from there next time. */
|
|
*p_err = HTTPc_ERR_TRANS_TX_BUF_FULL;
|
|
goto exit;
|
|
}
|
|
|
|
url_encode = HTTP_URL_EncodeStr(p_form_field->KeyPtr, /* Encode and Write to buffer the Key. */
|
|
p_buf_wr,
|
|
&str_len_key,
|
|
buf_len);
|
|
if (url_encode == DEF_FAIL) {
|
|
*p_err = HTTPc_ERR_REQ_FORM_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
p_buf_wr += str_len_key;
|
|
buf_len -= str_len_key;
|
|
|
|
*p_buf_wr = ASCII_CHAR_EQUALS_SIGN; /* Write the "=" sign. */
|
|
p_buf_wr++;
|
|
buf_len--;
|
|
|
|
url_encode = HTTP_URL_EncodeStr(p_form_field->ValPtr, /* Encode and Write to buffer the Value. */
|
|
p_buf_wr,
|
|
&str_len_val,
|
|
buf_len);
|
|
if (url_encode == DEF_FAIL) {
|
|
*p_err = HTTPc_ERR_REQ_FORM_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
p_buf_wr += str_len_val;
|
|
buf_len -= str_len_val;
|
|
|
|
if (i < (p_req->FormFieldNbr - 1)) {
|
|
*p_buf_wr = ASCII_CHAR_AMPERSAND; /* Write the "&" sign between pairs. */
|
|
p_buf_wr++;
|
|
buf_len--;
|
|
} else {
|
|
p_conn->ReqFormDataTxIx = 0;
|
|
}
|
|
|
|
p_form_field++;
|
|
}
|
|
|
|
*p_err = HTTPc_ERR_NONE;
|
|
|
|
|
|
exit:
|
|
p_conn->TxDataLen += (p_buf_wr - p_buf); /* Update Data Length to transmit. */
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* HTTPcReq_FormMultipart()
|
|
*
|
|
* Description : Prepare the multipart type form and copy it to HTTP buffer.
|
|
*
|
|
* 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 Form created and copied to buf successfully.
|
|
* HTTPc_ERR_REQ_FORM_FIELD_NULL_PTR Null pointer in form table.
|
|
* HTTPc_ERR_REQ_FORM_FIELD_INVALID_LEN Invalid value length pass in form table.
|
|
* HTTPc_ERR_REQ_FORM_CREATE Fatal error occurred in form creation.
|
|
* HTTPc_ERR_TRANS_BUF_LEN_INVALID HTTP buffer length is not enough big.
|
|
* HTTPc_ERR_TRANS_TX_BUF_FULL HTTP buffer is full, data must be Tx.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Caller(s) : HTTPcReq_Body().
|
|
*
|
|
* Note(s) : (1) Do not support Compression, Encryption and Encoding inside multipart.
|
|
* Only header Content-Disposition will be added with parameter "name". For file
|
|
* upload, parameter "filename" will be added also.
|
|
* Header Content-Type will be added if content-type passed is recognized by client.
|
|
*
|
|
* (2) Only support 1 level of multipart.
|
|
*********************************************************************************************************
|
|
*/
|
|
#if (HTTPc_CFG_FORM_EN == DEF_ENABLED)
|
|
static void HTTPcReq_FormMultipart(HTTPc_CONN *p_conn,
|
|
HTTPc_ERR *p_err)
|
|
{
|
|
HTTPc_CONN_OBJ *p_conn_const;
|
|
HTTPc_REQ *p_req;
|
|
HTTPc_REQ_OBJ *p_req_const;
|
|
CPU_CHAR *p_buf;
|
|
CPU_CHAR *p_buf_wr;
|
|
CPU_CHAR *p_str;
|
|
CPU_CHAR *p_name;
|
|
CPU_CHAR *p_filename;
|
|
HTTPc_FORM_TBL_FIELD *p_form_tbl;
|
|
HTTPc_FORM_TBL_FIELD *p_tbl_entry;
|
|
HTTPc_KEY_VAL *p_kvp;
|
|
HTTPc_KEY_VAL_EXT *p_kvp_big;
|
|
HTTPc_MULTIPART_FILE *p_multipart_file;
|
|
HTTP_DICT *p_entry;
|
|
CPU_SIZE_T name_field_len;
|
|
CPU_SIZE_T filename_field_len;
|
|
CPU_SIZE_T buf_len;
|
|
CPU_SIZE_T data_size;
|
|
CPU_INT16U data_len_wr;
|
|
CPU_INT16U name_char_encode_nbr;
|
|
CPU_INT16U filename_char_encode_nbr;
|
|
CPU_INT16U i;
|
|
CPU_BOOLEAN url_encode;
|
|
CPU_BOOLEAN done;
|
|
|
|
|
|
p_conn_const = (HTTPc_CONN_OBJ *)p_conn;
|
|
p_req = p_conn->ReqListHeadPtr;
|
|
p_req_const = (HTTPc_REQ_OBJ *)p_req;
|
|
|
|
p_buf = p_conn->TxBufPtr + p_conn->TxDataLen; /* Point to beginning of free space in Tx buffer. */
|
|
buf_len = p_conn->BufLen - p_conn->TxDataLen;
|
|
p_buf_wr = p_buf;
|
|
data_size = 0;
|
|
|
|
p_form_tbl = p_req->FormFieldTbl;
|
|
for (i = p_conn->ReqFormDataTxIx; i < p_req->FormFieldNbr; i++) {
|
|
|
|
p_tbl_entry = &p_form_tbl[i];
|
|
|
|
switch (p_conn->State) {
|
|
case HTTPc_CONN_STATE_REQ_BODY_FORM_MULTIPART_BOUNDARY:
|
|
/* Calculate size of needed for data to write. */
|
|
data_size = HTTPc_STR_BOUNDARY_START_LEN + STR_CR_LF_LEN;
|
|
|
|
if (data_size > p_conn->BufLen) { /* Validate that buffer size is enough big. */
|
|
*p_err = HTTPc_ERR_TRANS_BUF_LEN_INVALID;
|
|
goto exit;
|
|
}
|
|
|
|
if (data_size > buf_len) { /* Validate that remaining space in buffer is enough.*/
|
|
p_conn->TxDataLen += (p_buf_wr - p_buf);/* Update Data Length to transmit. */
|
|
p_conn->ReqFormDataTxIx = i; /* Save the tbl index to start from there next time. */
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_BODY_FORM_MULTIPART_BOUNDARY;
|
|
*p_err = HTTPc_ERR_TRANS_TX_BUF_FULL;
|
|
goto exit;
|
|
}
|
|
|
|
/* Write start of boundary. */
|
|
p_str = Str_Copy_N(p_buf_wr, HTTPc_STR_BOUNDARY_START, data_size);
|
|
if (p_str == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_FORM_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
p_str += HTTPc_STR_BOUNDARY_START_LEN;
|
|
|
|
/* Write CRLF after boundary. */
|
|
p_str = Str_Copy_N(p_str, STR_CR_LF, STR_CR_LF_LEN);
|
|
if (p_str == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_FORM_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
p_str += STR_CR_LF_LEN;
|
|
buf_len -= (p_str - p_buf_wr);
|
|
p_buf_wr = p_str;
|
|
/* 'break' intentionally omitted. */
|
|
|
|
|
|
case HTTPc_CONN_STATE_REQ_BODY_FORM_MULTIPART_HDR_CONTENT_DISPO:
|
|
switch (p_tbl_entry->Type) {
|
|
case HTTPc_FORM_FIELD_TYPE_KEY_VAL:
|
|
p_kvp = (HTTPc_KEY_VAL *)p_tbl_entry->FieldObjPtr;
|
|
/* Found nbr of chars to encode in name. */
|
|
name_field_len = p_kvp->KeyLen;
|
|
name_char_encode_nbr = HTTP_URL_CharEncodeNbr(p_kvp->KeyPtr, name_field_len);
|
|
p_name = p_kvp->KeyPtr;
|
|
p_filename = DEF_NULL;
|
|
break;
|
|
|
|
|
|
case HTTPc_FORM_FIELD_TYPE_KEY_VAL_EXT:
|
|
p_kvp_big = (HTTPc_KEY_VAL_EXT *)p_tbl_entry->FieldObjPtr;
|
|
/* Found nbr of chars to encode in name. */
|
|
name_field_len = p_kvp_big->KeyLen;
|
|
name_char_encode_nbr = HTTP_URL_CharEncodeNbr(p_kvp_big->KeyPtr, name_field_len);
|
|
p_name = p_kvp_big->KeyPtr;
|
|
p_filename = DEF_NULL;
|
|
break;
|
|
|
|
|
|
case HTTPc_FORM_FIELD_TYPE_FILE:
|
|
p_multipart_file = (HTTPc_MULTIPART_FILE *)p_tbl_entry->FieldObjPtr;
|
|
/* Found nbr of chars to encode in name. */
|
|
name_field_len = p_multipart_file->NameLen;
|
|
name_char_encode_nbr = HTTP_URL_CharEncodeNbr(p_multipart_file->NamePtr, name_field_len);
|
|
p_name = p_multipart_file->NamePtr;
|
|
/* Found nbr of chars to encode in filename. */
|
|
filename_field_len = p_multipart_file->FileNameLen;
|
|
filename_char_encode_nbr = HTTP_URL_CharEncodeNbr(p_multipart_file->FileNamePtr, filename_field_len);
|
|
p_filename = p_multipart_file->FileNamePtr;
|
|
data_size += (2 + /* "; " */
|
|
HTTP_STR_MULTIPART_FIELD_FILE_NAME_LEN + /* "filename" */
|
|
3 + /* "=\"\"" */
|
|
filename_field_len + /* "filename_rx_in_form" */
|
|
HTTP_URL_ENCODING_JUMP * filename_char_encode_nbr);/* nbr of char to encode. */
|
|
break;
|
|
|
|
|
|
default:
|
|
*p_err = HTTPc_ERR_FORM_TYPE_INVALID;
|
|
goto exit;
|
|
}
|
|
|
|
/* Calculate size needed for data to write. */
|
|
data_size += HTTP_STR_HDR_FIELD_CONTENT_DISPOSITION_LEN + /* "Content-Disposition" */
|
|
2 + /* ": " */
|
|
HTTP_STR_CONTENT_DISPOSITION_FORM_DATA_LEN + /* "form-data" */
|
|
2 + /* "; " */
|
|
HTTP_STR_MULTIPART_FIELD_NAME_LEN + /* "name" */
|
|
3 + /* "=\"\"" */
|
|
name_field_len + /* "name_rx_in_form" */
|
|
HTTP_URL_ENCODING_JUMP * name_char_encode_nbr + /* nbr of char to encode. */
|
|
STR_CR_LF_LEN; /* "\r\n" */
|
|
|
|
|
|
if (data_size > p_conn->BufLen) { /* Validate that buffer size is enough big. */
|
|
*p_err = HTTPc_ERR_TRANS_BUF_LEN_INVALID;
|
|
goto exit;
|
|
}
|
|
|
|
if (data_size > buf_len) { /* Validate that remaining space in buffer is enough. */
|
|
p_conn->TxDataLen += (p_buf_wr - p_buf); /* Update Data Length to transmit. */
|
|
p_conn->ReqFormDataTxIx = i; /* Save the tbl index to start from there next time. */
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_BODY_FORM_MULTIPART_HDR_CONTENT_DISPO;
|
|
*p_err = HTTPc_ERR_TRANS_TX_BUF_FULL;
|
|
goto exit;
|
|
}
|
|
/* Write Content-Disposition with name (and filename). */
|
|
p_str = HTTPcReq_HdrCopyToBuf(p_buf_wr,
|
|
p_conn->BufLen,
|
|
buf_len,
|
|
HTTP_HDR_FIELD_CONTENT_DISPOSITION,
|
|
HTTP_STR_CONTENT_DISPOSITION_FORM_DATA,
|
|
HTTP_STR_CONTENT_DISPOSITION_FORM_DATA_LEN,
|
|
DEF_NO,
|
|
p_err);
|
|
if (p_str == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_FORM_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
*p_str = ASCII_CHAR_SEMICOLON;
|
|
p_str++;
|
|
*p_str = ASCII_CHAR_SPACE;
|
|
p_str++;
|
|
|
|
p_str = Str_Copy_N(p_str, HTTP_STR_MULTIPART_FIELD_NAME, HTTP_STR_MULTIPART_FIELD_NAME_LEN);
|
|
if (p_str == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_FORM_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
p_str += HTTP_STR_MULTIPART_FIELD_NAME_LEN;
|
|
*p_str = ASCII_CHAR_EQUALS_SIGN;
|
|
p_str++;
|
|
*p_str = ASCII_CHAR_QUOTATION_MARK;
|
|
p_str++;
|
|
|
|
url_encode = HTTP_URL_EncodeStr(p_name,
|
|
p_str,
|
|
&name_field_len,
|
|
buf_len);
|
|
if (url_encode == DEF_FAIL) {
|
|
*p_err = HTTPc_ERR_REQ_FORM_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
p_str += name_field_len;
|
|
*p_str = ASCII_CHAR_QUOTATION_MARK;
|
|
p_str++;
|
|
|
|
if (p_filename != DEF_NULL) {
|
|
*p_str = ASCII_CHAR_SEMICOLON;
|
|
p_str++;
|
|
*p_str = ASCII_CHAR_SPACE;
|
|
p_str++;
|
|
|
|
p_str = Str_Copy_N(p_str, HTTP_STR_MULTIPART_FIELD_FILE_NAME, HTTP_STR_MULTIPART_FIELD_FILE_NAME_LEN);
|
|
if (p_str == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_FORM_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
p_str += HTTP_STR_MULTIPART_FIELD_FILE_NAME_LEN;
|
|
*p_str = ASCII_CHAR_EQUALS_SIGN;
|
|
p_str++;
|
|
*p_str = ASCII_CHAR_QUOTATION_MARK;
|
|
p_str++;
|
|
|
|
url_encode = HTTP_URL_EncodeStr(p_filename,
|
|
p_str,
|
|
&filename_field_len,
|
|
buf_len);
|
|
if (url_encode == DEF_FAIL) {
|
|
*p_err = HTTPc_ERR_REQ_FORM_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
p_str += filename_field_len;
|
|
*p_str = ASCII_CHAR_QUOTATION_MARK;
|
|
p_str++;
|
|
}
|
|
|
|
p_str = Str_Copy_N(p_str, STR_CR_LF, STR_CR_LF_LEN);
|
|
if (p_str == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_FORM_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
p_str += STR_CR_LF_LEN;
|
|
|
|
buf_len -= (p_str - p_buf_wr);
|
|
p_buf_wr = p_str;
|
|
/* 'break' intentionally omitted. */
|
|
|
|
|
|
case HTTPc_CONN_STATE_REQ_BODY_FORM_MULTIPART_HDR_CONTENT_TYPE:
|
|
switch (p_tbl_entry->Type) {
|
|
case HTTPc_FORM_FIELD_TYPE_KEY_VAL:
|
|
case HTTPc_FORM_FIELD_TYPE_KEY_VAL_EXT:
|
|
p_multipart_file = DEF_NULL;
|
|
break;
|
|
|
|
case HTTPc_FORM_FIELD_TYPE_FILE:
|
|
p_multipart_file = (HTTPc_MULTIPART_FILE *)p_tbl_entry->FieldObjPtr;
|
|
break;
|
|
|
|
default:
|
|
*p_err = HTTPc_ERR_FORM_TYPE_INVALID;
|
|
goto exit;
|
|
}
|
|
|
|
if (p_multipart_file != DEF_NULL) {
|
|
p_entry = HTTP_Dict_EntryGet(HTTP_Dict_ContentType,
|
|
HTTP_Dict_ContentTypeSize,
|
|
p_multipart_file->ContentType);
|
|
if (p_entry != DEF_NULL) {
|
|
|
|
p_str = HTTPcReq_HdrCopyToBuf(p_buf_wr,
|
|
p_conn->BufLen,
|
|
buf_len,
|
|
HTTP_HDR_FIELD_CONTENT_TYPE,
|
|
p_entry->StrPtr,
|
|
p_entry->StrLen,
|
|
DEF_YES,
|
|
p_err);
|
|
switch (*p_err) {
|
|
case HTTPc_ERR_NONE:
|
|
break;
|
|
|
|
case HTTPc_ERR_TRANS_TX_BUF_FULL:
|
|
/* Update Data Length to transmit. */
|
|
p_conn->TxDataLen += (p_buf_wr - p_buf);
|
|
p_conn->ReqFormDataTxIx = i; /* Save the tbl index to start from there next time. */
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_BODY_FORM_MULTIPART_HDR_CONTENT_TYPE;
|
|
goto exit;
|
|
|
|
case HTTPc_ERR_TRANS_BUF_LEN_INVALID:
|
|
case HTTPc_ERR_REQ_HDR_CREATE:
|
|
default:
|
|
goto exit;
|
|
}
|
|
}
|
|
}
|
|
|
|
buf_len -= (p_str - p_buf_wr);
|
|
p_buf_wr = p_str;
|
|
|
|
if (STR_CR_LF_LEN > p_conn->BufLen) { /* Validate that buffer size is enough big. */
|
|
*p_err = HTTPc_ERR_TRANS_BUF_LEN_INVALID;
|
|
goto exit;
|
|
}
|
|
|
|
if (STR_CR_LF_LEN > buf_len) { /* Validate that remaining space in buf is enough. */
|
|
p_conn->TxDataLen += (p_buf_wr - p_buf); /* Update Data Length to transmit. */
|
|
p_conn->ReqFormDataTxIx = i; /* Save the tbl index to start from there next time. */
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_BODY_FORM_MULTIPART_HDR_CONTENT_TYPE;
|
|
*p_err = HTTPc_ERR_TRANS_TX_BUF_FULL;
|
|
goto exit;
|
|
}
|
|
|
|
p_str = Str_Copy_N(p_str, STR_CR_LF, STR_CR_LF_LEN);
|
|
if (p_str == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_FORM_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
p_str += STR_CR_LF_LEN;
|
|
buf_len -= (p_str - p_buf_wr);
|
|
p_buf_wr = p_str;
|
|
/* 'break' intentionally omitted. */
|
|
|
|
|
|
case HTTPc_CONN_STATE_REQ_BODY_FORM_MULTIPART_DATA:
|
|
switch (p_tbl_entry->Type) {
|
|
case HTTPc_FORM_FIELD_TYPE_KEY_VAL:
|
|
p_kvp = (HTTPc_KEY_VAL *)p_tbl_entry->FieldObjPtr;
|
|
|
|
if (p_kvp->ValLen > p_conn->BufLen) { /* Validate that buffer size is enough big. */
|
|
*p_err = HTTPc_ERR_TRANS_BUF_LEN_INVALID;
|
|
goto exit;
|
|
}
|
|
|
|
if (p_kvp->ValLen > buf_len) { /* Validate that remaining space in buf is enough. */
|
|
p_conn->TxDataLen += (p_buf_wr - p_buf);/* Update Data Length to transmit. */
|
|
p_conn->ReqFormDataTxIx = i; /* Save the tbl index to start from there next time.*/
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_BODY_FORM_MULTIPART_DATA;
|
|
*p_err = HTTPc_ERR_TRANS_TX_BUF_FULL;
|
|
goto exit;
|
|
}
|
|
|
|
Mem_Copy(p_buf_wr, p_kvp->ValPtr, p_kvp->ValLen);
|
|
|
|
buf_len -= p_kvp->ValLen;;
|
|
p_buf_wr += p_kvp->ValLen;
|
|
break;
|
|
|
|
|
|
case HTTPc_FORM_FIELD_TYPE_KEY_VAL_EXT:
|
|
p_kvp_big = (HTTPc_KEY_VAL_EXT *)p_tbl_entry->FieldObjPtr;
|
|
|
|
done = p_kvp_big->OnValTx(p_conn_const,
|
|
p_req_const,
|
|
p_kvp_big,
|
|
p_buf_wr,
|
|
buf_len,
|
|
&data_len_wr);
|
|
|
|
p_conn->ReqDataOffset += data_len_wr;
|
|
|
|
if (data_len_wr > buf_len) {
|
|
*p_err = HTTPc_ERR_REQ_FORM_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
if (p_conn->ReqDataOffset > p_kvp_big->ValLen) {
|
|
*p_err = HTTPc_ERR_REQ_FORM_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
if ((done == DEF_YES) &&
|
|
(p_conn->ReqDataOffset < p_kvp_big->ValLen)) {
|
|
*p_err = HTTPc_ERR_REQ_FORM_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
buf_len -= data_len_wr;
|
|
p_buf_wr += data_len_wr;
|
|
|
|
if (done == DEF_NO) {
|
|
p_conn->TxDataLen += (p_buf_wr - p_buf);
|
|
p_conn->ReqFormDataTxIx = i; /* Save the tbl index to start from there next time.*/
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_BODY_FORM_MULTIPART_DATA;
|
|
*p_err = HTTPc_ERR_TRANS_TX_BUF_FULL;
|
|
goto exit;
|
|
} else {
|
|
p_conn->ReqDataOffset = 0;
|
|
}
|
|
break;
|
|
|
|
|
|
case HTTPc_FORM_FIELD_TYPE_FILE:
|
|
p_multipart_file = (HTTPc_MULTIPART_FILE *)p_tbl_entry->FieldObjPtr;
|
|
|
|
done = p_multipart_file->OnFileTx(p_conn_const,
|
|
p_req_const,
|
|
p_multipart_file,
|
|
p_buf_wr,
|
|
buf_len,
|
|
&data_len_wr);
|
|
|
|
p_conn->ReqDataOffset += data_len_wr;
|
|
|
|
if (data_len_wr > buf_len) {
|
|
*p_err = HTTPc_ERR_REQ_FORM_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
if (p_conn->ReqDataOffset > p_multipart_file->FileLen) {
|
|
*p_err = HTTPc_ERR_REQ_FORM_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
if ((done == DEF_YES) &&
|
|
(p_conn->ReqDataOffset < p_multipart_file->FileLen)) {
|
|
*p_err = HTTPc_ERR_REQ_FORM_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
buf_len -= data_len_wr;
|
|
p_buf_wr += data_len_wr;
|
|
|
|
if (done == DEF_NO) {
|
|
p_conn->TxDataLen += (p_buf_wr - p_buf);
|
|
p_conn->ReqFormDataTxIx = i; /* Save the tbl index to start from there next time.*/
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_BODY_FORM_MULTIPART_DATA;
|
|
*p_err = HTTPc_ERR_TRANS_TX_BUF_FULL;
|
|
goto exit;
|
|
} else {
|
|
p_conn->ReqDataOffset = 0;
|
|
}
|
|
break;
|
|
|
|
|
|
default:
|
|
*p_err = HTTPc_ERR_FORM_TYPE_INVALID;
|
|
goto exit;
|
|
}
|
|
/* 'break' intentionally omitted. */
|
|
|
|
|
|
case HTTPc_CONN_STATE_REQ_BODY_FORM_MULTIPART_DATA_END:
|
|
|
|
p_conn->TxDataPtr = p_conn->TxBufPtr; /* Reset TxDataPtr to the HTTP buffer pointer. */
|
|
|
|
if (STR_CR_LF_LEN > p_conn->BufLen) { /* Validate that buffer size is enough big. */
|
|
*p_err = HTTPc_ERR_TRANS_BUF_LEN_INVALID;
|
|
goto exit;
|
|
}
|
|
|
|
if (STR_CR_LF_LEN > buf_len) { /* Validate that remaining space in buffer is enough. */
|
|
p_conn->TxDataLen += (p_buf_wr - p_buf); /* Update Data Length to transmit. */
|
|
p_conn->ReqFormDataTxIx = i; /* Save the tbl index to start from there next time. */
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_BODY_FORM_MULTIPART_DATA_END;
|
|
*p_err = HTTPc_ERR_TRANS_TX_BUF_FULL;
|
|
goto exit;
|
|
}
|
|
|
|
p_str = Str_Copy_N(p_buf_wr, STR_CR_LF, STR_CR_LF_LEN);
|
|
if (p_str == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_FORM_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
p_str += STR_CR_LF_LEN;
|
|
buf_len -= (p_str - p_buf_wr);
|
|
p_buf_wr = p_str;
|
|
/* 'break' intentionally omitted. */
|
|
|
|
|
|
case HTTPc_CONN_STATE_REQ_BODY_FORM_MULTIPART_BOUNDARY_END:
|
|
if (i == (p_req->FormFieldNbr - 1)) {
|
|
/* ----------- WRITE END OF BOUNDARY + CRLF ----------- */
|
|
/* Calculate size of needed for data to write. */
|
|
data_size = Str_Len(HTTPc_STR_BOUNDARY_END) + STR_CR_LF_LEN;
|
|
|
|
if (data_size > p_conn->BufLen) { /* Validate that buffer size is enough big. */
|
|
*p_err = HTTPc_ERR_TRANS_BUF_LEN_INVALID;
|
|
goto exit;
|
|
}
|
|
|
|
if (data_size > buf_len) {
|
|
p_conn->TxDataLen += (p_buf_wr - p_buf);
|
|
p_conn->ReqFormDataTxIx = i;
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_BODY_FORM_MULTIPART_BOUNDARY_END;
|
|
*p_err = HTTPc_ERR_TRANS_TX_BUF_FULL;
|
|
goto exit;
|
|
}
|
|
|
|
/* Write end of boundary. */
|
|
p_str = Str_Copy_N(p_buf_wr, HTTPc_STR_BOUNDARY_END, HTTPc_STR_BOUNDARY_END_LEN);
|
|
if (p_str == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_FORM_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
p_str += HTTPc_STR_BOUNDARY_END_LEN;
|
|
/* Write CRLF after last boundary. */
|
|
p_str = Str_Copy_N(p_str, STR_CR_LF, STR_CR_LF_LEN);
|
|
if (p_str == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_FORM_CREATE;
|
|
goto exit;
|
|
}
|
|
|
|
p_str += STR_CR_LF_LEN;
|
|
buf_len -= (p_str - p_buf_wr);
|
|
p_buf_wr = p_str;
|
|
}
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_BODY_FORM_MULTIPART_BOUNDARY;
|
|
break;
|
|
|
|
|
|
default:
|
|
*p_err = HTTPc_ERR_CONN_INVALID_STATE;
|
|
goto exit;
|
|
}
|
|
}
|
|
|
|
p_conn->TxDataLen += (p_buf_wr - p_buf);
|
|
|
|
p_conn->ReqFormDataTxIx = 0;
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_END;
|
|
|
|
*p_err = HTTPc_ERR_NONE;
|
|
|
|
|
|
exit:
|
|
return;
|
|
}
|
|
#endif
|
|
|
|
|
|
/*
|
|
*********************************************************************************************************
|
|
* HTTPcReq_BodyData()
|
|
*
|
|
* Description : Prepare and transmit Data passed by the application.
|
|
*
|
|
* 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 transfer is taken place successfully.
|
|
* HTTPc_ERR_REQ_BODY_CHUNK_PREPARE Fatal error occurred in chunk preparation.
|
|
* HTTPc_ERR_CONN_INVALID_STATE HTTPc Connection invalid state.
|
|
*
|
|
* Return(s) : None.
|
|
*
|
|
* Caller(s) : HTTPcReq_Body().
|
|
*
|
|
* Note(s) : (1) Data can be send with the chunked transfer-encoding or with header Content-Length
|
|
* when data length is known.
|
|
*********************************************************************************************************
|
|
*/
|
|
|
|
static void HTTPcReq_BodyData(HTTPc_CONN *p_conn,
|
|
HTTPc_ERR *p_err)
|
|
{
|
|
HTTPc_REQ *p_req;
|
|
CPU_SIZE_T buf_len;
|
|
CPU_BOOLEAN chunk_en;
|
|
HTTPc_CONN_OBJ *p_conn_const;
|
|
HTTPc_REQ_OBJ *p_req_const;
|
|
CPU_CHAR *p_buf;
|
|
CPU_CHAR *p_buf_wr;
|
|
#if (HTTPc_CFG_CHUNK_TX_EN == DEF_ENABLED)
|
|
CPU_SIZE_T nbr_dig_max;
|
|
CPU_SIZE_T data_size;
|
|
CPU_CHAR *p_str;
|
|
CPU_BOOLEAN last_chunk;
|
|
#endif
|
|
|
|
|
|
p_req = p_conn->ReqListHeadPtr;
|
|
p_conn_const = (HTTPc_CONN_OBJ *)p_conn;
|
|
p_req_const = (HTTPc_REQ_OBJ *)p_req;
|
|
|
|
p_buf = p_conn->TxBufPtr + p_conn->TxDataLen; /* Point to beginning of free space in Tx buffer. */
|
|
buf_len = p_conn->BufLen - p_conn->TxDataLen;
|
|
p_buf_wr = p_buf;
|
|
|
|
chunk_en = DEF_BIT_IS_SET(p_req->Flags, HTTPc_FLAG_REQ_BODY_CHUNK_TRANSFER);
|
|
|
|
if ((p_conn->TxDataLen != 0u) &&
|
|
(p_req->DataPtr != DEF_NULL)) {
|
|
*p_err = HTTPc_ERR_NONE;
|
|
goto exit;
|
|
}
|
|
|
|
/* -------------- STANDARD TRANSFER MODE -------------- */
|
|
if (chunk_en == DEF_NO) {
|
|
|
|
/* Call hook fnct to setup data pointer. */
|
|
(void)p_req->OnBodyTx(p_conn_const,
|
|
p_req_const,
|
|
&p_req->DataPtr,
|
|
p_buf_wr,
|
|
buf_len,
|
|
&p_conn->ReqDataOffset);
|
|
|
|
if (p_conn->ReqDataOffset == 0) {
|
|
*p_err = HTTPc_ERR_NONE;
|
|
goto exit;
|
|
}
|
|
|
|
|
|
if (p_req->DataPtr == DEF_NULL) { /* Case 1: Data was copied in Tx buffer. */
|
|
|
|
if (p_conn->ReqDataOffset > buf_len) {
|
|
*p_err = HTTPc_ERR_REQ_BODY_CHUNK_INVALID;
|
|
goto exit;
|
|
}
|
|
p_conn->TxDataPtr = p_conn->TxBufPtr; /* Set TxDataPtr to HTTP buffer ptr. */
|
|
|
|
} else { /* Case 2: Application Data Pointer was passed. */
|
|
p_conn->TxDataPtr = p_req->DataPtr; /* Set pointer to data to Tx. */
|
|
}
|
|
|
|
p_conn->TxDataLen += p_conn->ReqDataOffset; /* Update Data Length to transmit. */
|
|
|
|
|
|
if (p_conn->ReqDataOffset > p_req->ContentLen) {
|
|
*p_err = HTTPc_ERR_REQ_BODY_CHUNK_INVALID;
|
|
goto exit;
|
|
}
|
|
|
|
p_req->ContentLen -= p_conn->ReqDataOffset; /* Calculate size of data remaining to Tx. */
|
|
|
|
if (p_req->ContentLen <= 0) { /* Return if all data sent. */
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_END;
|
|
*p_err = HTTPc_ERR_NONE;
|
|
goto exit;
|
|
}
|
|
|
|
/* --------------- CHUNK TRANSFER MODE ---------------- */
|
|
} else {
|
|
#if (HTTPc_CFG_CHUNK_TX_EN == DEF_ENABLED)
|
|
|
|
switch (p_conn->State) {
|
|
case HTTPc_CONN_STATE_REQ_BODY_DATA:
|
|
nbr_dig_max = HTTP_StrSizeHexDigReq(p_conn->BufLen);
|
|
data_size = nbr_dig_max + STR_CR_LF_LEN;
|
|
|
|
if (data_size >= p_conn->BufLen) {
|
|
*p_err = HTTPc_ERR_TRANS_BUF_LEN_INVALID;
|
|
goto exit;
|
|
}
|
|
|
|
if (data_size >= buf_len) {
|
|
*p_err = HTTPc_ERR_TRANS_TX_BUF_FULL;
|
|
goto exit;
|
|
}
|
|
|
|
p_buf_wr += data_size;
|
|
buf_len -= data_size;
|
|
|
|
/* Call hook fnct to setup data pointer. */
|
|
last_chunk = p_req->OnBodyTx(p_conn_const,
|
|
p_req_const,
|
|
&p_req->DataPtr,
|
|
p_buf_wr,
|
|
buf_len,
|
|
(CPU_INT16U *)&p_req->ContentLen); /* Use ContentLen to store length of chunk. */
|
|
|
|
if ((p_req->ContentLen == 0) &&
|
|
(last_chunk == DEF_NO)) {
|
|
*p_err = HTTPc_ERR_REQ_BODY_CHUNK_INVALID;
|
|
goto exit;
|
|
}
|
|
|
|
if (p_req->DataPtr == DEF_NULL) { /* Case 1: Data was copied in Tx buffer. */
|
|
|
|
if (p_req->ContentLen > buf_len) {
|
|
*p_err = HTTPc_ERR_REQ_BODY_CHUNK_INVALID;
|
|
goto exit;
|
|
}
|
|
|
|
p_conn->TxDataPtr = p_conn->TxBufPtr; /* Set TxDataPtr to HTTP buffer ptr. */
|
|
|
|
} else { /* Case 2: Application data pointer was passed. */
|
|
p_conn->TxDataPtr = p_req->DataPtr;
|
|
}
|
|
|
|
if (last_chunk == DEF_YES) {
|
|
DEF_BIT_SET(p_conn->ReqFlags, HTTPc_FLAG_REQ_BODY_CHUNK_LAST);
|
|
} else {
|
|
DEF_BIT_CLR(p_conn->ReqFlags, HTTPc_FLAG_REQ_BODY_CHUNK_LAST);
|
|
}
|
|
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_BODY_DATA_CHUNK_SIZE;
|
|
/* 'break' intentionally omitted. */
|
|
|
|
|
|
case HTTPc_CONN_STATE_REQ_BODY_DATA_CHUNK_SIZE:
|
|
nbr_dig_max = HTTP_StrSizeHexDigReq(p_conn->BufLen);
|
|
data_size = nbr_dig_max + STR_CR_LF_LEN;
|
|
p_buf_wr -= data_size;
|
|
buf_len = data_size;
|
|
|
|
p_str = HTTP_ChunkTransferWrSize(p_buf_wr, buf_len, nbr_dig_max, p_req->ContentLen);
|
|
if (p_str == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_BODY_CHUNK_PREPARE;
|
|
goto exit;
|
|
}
|
|
|
|
/* Update Data Length to transmit. */
|
|
if (p_conn->TxDataPtr == p_conn->TxBufPtr) {
|
|
p_conn->TxDataLen += (p_str - p_buf_wr) + p_req->ContentLen;
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_BODY_DATA_CHUNK_END;
|
|
} else {
|
|
p_conn->TxDataLen += (p_str - p_buf_wr);
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_BODY_DATA_CHUNK_DATA;
|
|
}
|
|
|
|
p_conn->TxDataPtr = p_conn->TxBufPtr; /* Set TxDataPtr to HTTP buffer ptr. */
|
|
break;
|
|
|
|
|
|
case HTTPc_CONN_STATE_REQ_BODY_DATA_CHUNK_DATA:
|
|
p_conn->TxDataLen += p_req->ContentLen; /* Update Data Length to transmit. */
|
|
p_conn->TxDataPtr = p_req->DataPtr; /* Set TxDataPtr to App data ptr. */
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_BODY_DATA_CHUNK_END;
|
|
break;
|
|
|
|
|
|
case HTTPc_CONN_STATE_REQ_BODY_DATA_CHUNK_END:
|
|
nbr_dig_max = HTTP_StrSizeHexDigReq(p_conn->BufLen);
|
|
data_size = nbr_dig_max + 3 * STR_CR_LF_LEN;
|
|
|
|
if (data_size > p_conn->BufLen) {
|
|
*p_err = HTTPc_ERR_TRANS_BUF_LEN_INVALID;
|
|
goto exit;
|
|
}
|
|
|
|
if (data_size > buf_len) {
|
|
*p_err = HTTPc_ERR_TRANS_TX_BUF_FULL;
|
|
goto exit;
|
|
}
|
|
|
|
p_str = Str_Copy_N(p_buf_wr, STR_CR_LF, STR_CR_LF_LEN);
|
|
if (p_str == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_BODY_CHUNK_PREPARE;
|
|
goto exit;
|
|
}
|
|
|
|
p_str += STR_CR_LF_LEN;
|
|
buf_len -= STR_CR_LF_LEN;
|
|
p_buf_wr = p_str;
|
|
|
|
p_conn->TxDataPtr = p_conn->TxBufPtr; /* Set TxDataPtr to internal buffer. */
|
|
|
|
p_conn->TxDataLen += STR_CR_LF_LEN; /* Update Data Length to transmit. */
|
|
|
|
last_chunk = DEF_BIT_IS_SET(p_conn->ReqFlags, HTTPc_FLAG_REQ_BODY_CHUNK_LAST);
|
|
if (last_chunk == DEF_YES) {
|
|
|
|
p_str = HTTP_ChunkTransferWrSize(p_buf_wr, buf_len, nbr_dig_max, 0);
|
|
if (p_str == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_BODY_CHUNK_PREPARE;
|
|
goto exit;
|
|
}
|
|
|
|
p_conn->TxDataLen += (p_str - p_buf_wr); /* Update Data Length to transmit. */
|
|
p_buf_wr = p_str;
|
|
|
|
p_str = Str_Copy_N(p_buf_wr, STR_CR_LF, STR_CR_LF_LEN);
|
|
if (p_str == DEF_NULL) {
|
|
*p_err = HTTPc_ERR_REQ_BODY_CHUNK_PREPARE;
|
|
goto exit;
|
|
}
|
|
|
|
p_str += STR_CR_LF_LEN;
|
|
|
|
p_conn->TxDataLen += (p_str - p_buf_wr); /* Update Data Length to transmit. */
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_END;
|
|
|
|
} else {
|
|
p_conn->State = HTTPc_CONN_STATE_REQ_BODY_DATA;
|
|
}
|
|
break;
|
|
|
|
|
|
default:
|
|
*p_err = HTTPc_ERR_CONN_INVALID_STATE;
|
|
goto exit;
|
|
}
|
|
#else
|
|
*p_err = HTTPc_ERR_FEATURE_DIS;
|
|
goto exit;
|
|
#endif
|
|
}
|
|
|
|
*p_err = HTTPc_ERR_NONE;
|
|
|
|
|
|
exit:
|
|
return;
|
|
}
|