Permalink
Newer
100644
2852 lines (2551 sloc)
127 KB
1
/***************************************************************************//**
2
* @file
3
* @brief Network - HTTP Server Request Module
4
*******************************************************************************
5
* # License
6
* <b>Copyright 2018 Silicon Laboratories Inc. www.silabs.com</b>
7
*******************************************************************************
8
*
9
* The licensor of this software is Silicon Laboratories Inc. Your use of this
10
* software is governed by the terms of Silicon Labs Master Software License
11
* Agreement (MSLA) available at
12
* www.silabs.com/about-us/legal/master-software-license-agreement.
13
* The software is governed by the sections of the MSLA applicable to Micrium
14
* Software.
15
*
16
******************************************************************************/
17
18
/********************************************************************************************************
19
********************************************************************************************************
20
* DEPENDENCIES & AVAIL CHECK(S)
21
********************************************************************************************************
22
*******************************************************************************************************/
23
24
#include <rtos_description.h>
25
26
#if (defined(RTOS_MODULE_NET_HTTP_SERVER_AVAIL))
27
28
#if (!defined(RTOS_MODULE_NET_AVAIL))
29
#error HTTP Server Module requires Network Core module. Make sure it is part of your project \
30
and that RTOS_MODULE_NET_AVAIL is defined in rtos_description.h.
31
#endif
32
33
/********************************************************************************************************
34
********************************************************************************************************
35
* INCLUDE FILES
36
********************************************************************************************************
37
*******************************************************************************************************/
38
39
#include "http_server_priv.h"
40
41
#include "../http_priv.h"
42
#include "../http_dict_priv.h"
43
44
#include <cpu/include/cpu.h>
45
#include <common/include/lib_ascii.h>
46
#include <common/include/lib_str.h>
47
48
#include <common/source/rtos/rtos_utils_priv.h>
49
#include <common/source/logging/logging_priv.h>
50
51
/********************************************************************************************************
52
********************************************************************************************************
53
* LOCAL DEFINES
54
********************************************************************************************************
55
*******************************************************************************************************/
56
57
#define LOG_DFLT_CH (NET, HTTP)
58
#define RTOS_MODULE_CUR RTOS_CFG_MODULE_NET
59
60
/********************************************************************************************************
61
* FORM DEFINES
62
*******************************************************************************************************/
63
64
#define HTTPs_STR_MULTIPART_CTRL_END_SEC STR_CR_LF STR_CR_LF
65
#define HTTPs_STR_MULTIPART_CTRL_END_SEC_LEN (sizeof(HTTPs_STR_MULTIPART_CTRL_END_SEC) - 1)
66
67
#define HTTPs_STR_MULTIPART_DATA_START "--"
68
#define HTTPs_STR_MULTIPART_DATA_START_LEN (sizeof(HTTPs_STR_MULTIPART_DATA_START) - 1)
69
70
#define HTTPs_STR_MULTIPART_DATA_END STR_CR_LF "--"
71
#define HTTPs_STR_MULTIPART_DATA_END_LEN (sizeof(HTTPs_STR_MULTIPART_DATA_END) - 1)
72
73
#define HTTPs_STR_MULTIPART_LAST "--" STR_CR_LF
74
#define HTTPs_STR_MULTIPART_LAST_LEN (sizeof(HTTPs_STR_MULTIPART_LAST) - 1)
75
76
/********************************************************************************************************
77
********************************************************************************************************
78
* LOCAL FUNCTION PROTOTYPES
79
********************************************************************************************************
80
*******************************************************************************************************/
81
82
static void HTTPsReq_MethodParse(HTTPs_INSTANCE *p_instance,
83
HTTPs_CONN *p_conn,
84
HTTPs_ERR *p_err);
85
86
static CPU_BOOLEAN HTTPsReq_URI_Parse(HTTPs_INSTANCE *p_instance,
87
HTTPs_CONN *p_conn,
88
HTTPs_ERR *p_err);
89
90
static void HTTPsReq_QueryStrParse(HTTPs_INSTANCE *p_instance,
91
HTTPs_CONN *p_conn,
92
HTTPs_ERR *p_err);
93
94
#if (HTTPs_CFG_QUERY_STR_EN == DEF_ENABLED)
95
static CPU_BOOLEAN HTTPsReq_QueryStrKeyValBlkAdd(HTTPs_INSTANCE *p_instance,
96
HTTPs_CONN *p_conn,
97
CPU_CHAR *p_str,
98
CPU_SIZE_T str_len,
99
HTTPs_ERR *p_err);
100
#endif
101
102
static void HTTPsReq_ProtocolVerParse(HTTPs_INSTANCE *p_instance,
103
HTTPs_CONN *p_conn,
104
HTTPs_ERR *p_err);
105
106
static void HTTPsReq_HdrParse(HTTPs_INSTANCE *p_instance,
107
HTTPs_CONN *p_conn,
108
HTTPs_ERR *p_err);
109
110
static CPU_CHAR *HTTPsReq_HdrParseValGet(CPU_CHAR *p_field,
111
CPU_INT16U field_len,
112
CPU_CHAR *p_field_end,
113
CPU_INT16U *p_len_rem);
114
115
#if (HTTPs_CFG_FORM_EN == DEF_ENABLED)
116
static CPU_BOOLEAN HTTPsReq_BodyForm(HTTPs_INSTANCE *p_instance,
117
HTTPs_CONN *p_conn,
118
HTTPs_ERR *p_err);
119
120
static CPU_BOOLEAN HTTPsReq_BodyFormAppParse(HTTPs_INSTANCE *p_instance,
121
HTTPs_CONN *p_connn,
122
HTTPs_ERR *p_err);
123
124
static CPU_BOOLEAN HTTPsReq_BodyFormAppKeyValBlkAdd(HTTPs_INSTANCE *p_instance,
125
HTTPs_CONN *p_conn,
126
CPU_CHAR *p_str,
127
CPU_SIZE_T str_len,
128
HTTPs_ERR *p_err);
129
130
#if (HTTPs_CFG_FORM_MULTIPART_EN == DEF_ENABLED)
131
static CPU_BOOLEAN HTTPsReq_BodyFormMultipartParse(HTTPs_INSTANCE *p_instance,
132
HTTPs_CONN *p_conn,
133
HTTPs_ERR *p_err);
134
135
static CPU_CHAR *HTTPsReq_BodyFormMultipartBoundarySrch(CPU_CHAR *p_boundary,
136
CPU_INT08U boundary_len,
137
CPU_CHAR *p_buf,
138
CPU_INT16U buf_len,
139
CPU_CHAR **p_boundary_sep);
140
141
static CPU_BOOLEAN HTTPsReq_BodyFormMultipartCtrlParse(HTTPs_INSTANCE *p_instance,
142
HTTPs_CONN *p_conn,
143
HTTPs_ERR *p_err);
144
145
static CPU_BOOLEAN HTTPsReq_BodyFormMultipartFileWr(HTTPs_INSTANCE *p_instance,
146
HTTPs_CONN *p_conn,
147
HTTPs_ERR *p_err);
148
#endif
149
#endif
150
151
#if ((HTTPs_CFG_QUERY_STR_EN == DEF_ENABLED) \
152
|| ((HTTPs_CFG_FORM_EN == DEF_ENABLED)))
153
static CPU_BOOLEAN HTTPsReq_URL_EncodeStrParse(HTTPs_INSTANCE *p_instance,
154
HTTPs_CONN *p_conn,
155
HTTPs_KEY_VAL *p_key_val,
156
CPU_BOOLEAN from_query,
157
CPU_CHAR *p_str,
158
CPU_SIZE_T str_len);
159
#endif
160
161
/********************************************************************************************************
162
********************************************************************************************************
163
* GLOBAL FUNCTIONS
164
********************************************************************************************************
165
*******************************************************************************************************/
166
167
/****************************************************************************************************//**
168
* HTTPsReq_Handler()
169
*
170
* @brief (1) Parse request:
171
* - (a) Parse request method
172
* - (b) Parse request URI
173
* - (c) Parse request query string (if necessary)
174
* - (d) Parse request protocol version
175
* - (e) Parse request headers
176
* - (f) (HOOK) Authentication
177
*
178
* @param p_instance Pointer to the instance.
179
*
180
* @param p_conn Pointer to the connection.
181
*
182
* @return HTTPs_CONN_PROCESS_CONTINUE, connection successfully updated and the process can continue.
183
* HTTPs_CONN_PROCESS_RX_TX, connection requires more data to complete the parse process.
184
*
185
* @note (2) RFC #2616, Section 5 'Request' specifies how a request message must be structured:
186
** A request message from a client to a server includes, within the first line of that message,
187
* the method to be applied to the resource, the identifier of the resource, and the protocol
188
* version in use.
189
*
190
* Request = Request-Line
191
* *(( general-header
192
* | request-header
193
* | entity-header ) CRLF)
194
* CRLF
195
* [ message-body ]
196
*******************************************************************************************************/
197
void HTTPsReq_Handler(HTTPs_INSTANCE *p_instance,
198
HTTPs_CONN *p_conn)
199
{
200
const HTTPs_CFG *p_cfg;
201
HTTPs_INSTANCE_STATS *p_ctr_stats = DEF_NULL;
202
HTTPs_INSTANCE_ERRS *p_ctr_err = DEF_NULL;
203
CPU_BOOLEAN accepted;
204
CPU_BOOLEAN done;
205
CPU_BOOLEAN hook_def;
206
CPU_BOOLEAN is_query_str_found;
207
HTTPs_ERR err_http = HTTPs_ERR_NONE;
208
209
p_cfg = (HTTPs_CFG *)p_instance->CfgPtr;
210
211
HTTPs_SET_PTR_STATS(p_ctr_stats, p_instance);
212
HTTPs_SET_PTR_ERRS(p_ctr_err, p_instance);
213
214
done = DEF_NO;
215
while (done != DEF_YES) {
216
switch (p_conn->State) {
217
case HTTPs_CONN_STATE_REQ_INIT:
218
LOG_VRB(("HTTPs - SockID: ", (u)p_conn->SockID, " - New Request received"));
219
HTTPs_STATS_INC(p_ctr_stats->Req_StatRxdCtr);
220
#if (HTTPs_CFG_HDR_RX_EN == DEF_ENABLED)
221
p_conn->HdrType = HTTPs_HDR_TYPE_REQ;
222
#endif
223
p_conn->State = HTTPs_CONN_STATE_REQ_PARSE_METHOD;
224
break;
225
226
// ---------------- PARSE REQ METHOD ------------------
227
case HTTPs_CONN_STATE_REQ_PARSE_METHOD:
228
HTTPsReq_MethodParse(p_instance, p_conn, &err_http);
229
if (err_http != HTTPs_ERR_NONE) { // If the Method parsing has failed...
230
HTTPs_ERR_INC(p_ctr_err->Req_ErrInvalidCtr); // ...generate an error...
231
p_conn->ErrCode = err_http;
232
p_conn->State = HTTPs_CONN_STATE_ERR_INTERNAL;
233
p_conn->SockState = HTTPs_SOCK_STATE_NONE;
234
done = DEF_YES; // ...and exit the state machine.
235
break;
236
}
237
// If the Method parsing is successful...
238
p_conn->State = HTTPs_CONN_STATE_REQ_PARSE_URI; // ...go to the next step.
239
break;
240
241
// ------------------ PARSE REQ URI -------------------
242
case HTTPs_CONN_STATE_REQ_PARSE_URI:
243
is_query_str_found = HTTPsReq_URI_Parse(p_instance, p_conn, &err_http);
244
switch (err_http) {
245
case HTTPs_ERR_NONE: // If the URI parsing is successful...
246
if (is_query_str_found == DEF_YES) { // ...check if query string need to be parse.
247
p_conn->State = HTTPs_CONN_STATE_REQ_PARSE_QUERY_STRING;
248
} else {
249
p_conn->State = HTTPs_CONN_STATE_REQ_PARSE_PROTOCOL_VERSION;
250
}
251
break;
252
253
case HTTPs_ERR_REQ_MORE_DATA_REQUIRED: // If more data is required to complete the...
254
p_conn->SockState = HTTPs_SOCK_STATE_RX; // ...URI Parsing, exit the state machine.
255
done = DEF_YES;
256
break;
257
258
default: // If the URI parsing has failed...
259
HTTPs_ERR_INC(p_ctr_err->Req_ErrInvalidCtr); // ...generate an error...
260
p_conn->SockState = HTTPs_SOCK_STATE_NONE;
261
p_conn->ErrCode = err_http;
262
p_conn->State = HTTPs_CONN_STATE_ERR_INTERNAL;
263
done = DEF_YES; // ...and exit the state machine.
264
break;
265
}
266
break;
267
268
// --------------- PARSE REQ QUERY STR ----------------
269
case HTTPs_CONN_STATE_REQ_PARSE_QUERY_STRING:
270
HTTPsReq_QueryStrParse(p_instance, p_conn, &err_http);
271
switch (err_http) {
272
case HTTPs_ERR_NONE: // If the Query Str parsing is successful...
273
// ...go to the next step.
274
p_conn->State = HTTPs_CONN_STATE_REQ_PARSE_PROTOCOL_VERSION;
275
break;
276
277
case HTTPs_ERR_REQ_MORE_DATA_REQUIRED: // If more data is required to complete the...
278
p_conn->SockState = HTTPs_SOCK_STATE_RX; // ...Query Str Parsing, exit the state machine.
279
done = DEF_YES;
280
break;
281
282
default: // If the Query Str parsing has failed...
283
HTTPs_ERR_INC(p_ctr_err->Req_ErrInvalidCtr); // ...generate an error...
284
p_conn->SockState = HTTPs_SOCK_STATE_NONE;
285
p_conn->ErrCode = err_http;
286
p_conn->State = HTTPs_CONN_STATE_ERR_INTERNAL;
287
done = DEF_YES; // ...and exit the state machine.
288
break;
289
}
290
break;
291
292
// -------------- PARSE REQ PROTOCOL VER --------------
293
case HTTPs_CONN_STATE_REQ_PARSE_PROTOCOL_VERSION:
294
HTTPsReq_ProtocolVerParse(p_instance, p_conn, &err_http);
295
switch (err_http) {
296
case HTTPs_ERR_NONE: // If the Protocol Ver parsing is successful...
297
// ...go to the next step.
298
p_conn->State = HTTPs_CONN_STATE_REQ_PARSE_HDR;
299
p_conn->SockState = HTTPs_SOCK_STATE_NONE;
300
DEF_BIT_CLR(p_conn->Flags, (HTTPs_FLAGS)HTTPs_FLAG_RESP_LOCATION);
301
break;
302
303
case HTTPs_ERR_REQ_MORE_DATA_REQUIRED: // If more data is required to complete the...
304
p_conn->SockState = HTTPs_SOCK_STATE_RX; // ...Protocol Ver parsing, exit the state...
305
done = DEF_YES; // ...machine.
306
break;
307
308
default: // If the Protocol Ver parsing has failed...
309
HTTPs_ERR_INC(p_ctr_err->Req_ErrInvalidCtr); // ...generate an error...
310
p_conn->SockState = HTTPs_SOCK_STATE_NONE;
311
p_conn->ErrCode = err_http;
312
p_conn->State = HTTPs_CONN_STATE_ERR_INTERNAL;
313
done = DEF_YES; // ...and exit the state machine.
314
break;
315
}
316
break;
317
318
// ------------------ PARSE REQ HDR -------------------
319
case HTTPs_CONN_STATE_REQ_PARSE_HDR:
320
HTTPsReq_HdrParse(p_instance, p_conn, &err_http); // See Note #2.
321
switch (err_http) {
322
case HTTPs_ERR_NONE: // If the Protocol Ver parsing is successful...
323
// ...go to the next step.
324
p_conn->State = HTTPs_CONN_STATE_REQ_LINE_HDR_HOOK;
325
p_conn->SockState = HTTPs_SOCK_STATE_NONE;
326
HTTPs_STATS_INC(p_ctr_stats->Req_StatProcessedCtr);
327
break;
328
329
case HTTPs_ERR_REQ_MORE_DATA_REQUIRED: // If more data is required to complete the...
330
p_conn->SockState = HTTPs_SOCK_STATE_RX; // ...Protocol Ver parsing, exit the state...
331
done = DEF_YES; // ...machine.
332
break;
333
334
default: // If the Header parsing has failed...
335
HTTPs_ERR_INC(p_ctr_err->Req_ErrInvalidCtr); // ...generate an error...
336
p_conn->ErrCode = err_http;
337
p_conn->State = HTTPs_CONN_STATE_ERR_INTERNAL;
338
done = DEF_YES; // ...and exit the state machine.
339
break;
340
}
341
break;
342
343
// --------------- CONN REQ EXT PROCESS ---------------
344
case HTTPs_CONN_STATE_REQ_LINE_HDR_HOOK:
345
hook_def = HTTPs_HOOK_DEFINED(p_cfg->HooksPtr, OnReqHook);
346
if (hook_def == DEF_YES) {
347
accepted = p_cfg->HooksPtr->OnReqHook(p_instance,
348
p_conn,
349
p_cfg->Hooks_CfgPtr);
350
if (accepted != DEF_YES) {
351
// If the connection is not authorized ...
352
if (p_conn->StatusCode == HTTP_STATUS_OK) {
353
p_conn->StatusCode = HTTP_STATUS_UNAUTHORIZED;
354
}
355
DEF_BIT_SET(p_conn->Flags, HTTPs_FLAG_REQ_FLUSH);
356
p_conn->State = HTTPs_CONN_STATE_REQ_BODY_FLUSH_DATA;
357
}
358
}
359
// Otherwise, receive the body.
360
p_conn->State = HTTPs_CONN_STATE_REQ_BODY_INIT;
361
done = DEF_YES; // ... exit the state machine.
362
break;
363
364
default:
365
HTTPs_ERR_INC(p_ctr_err->Req_ErrStateUnkownCtr);
366
p_conn->ErrCode = HTTPs_ERR_STATE_UNKNOWN;
367
p_conn->State = HTTPs_CONN_STATE_ERR_INTERNAL;
368
done = DEF_YES;
369
RTOS_CRITICAL_FAIL_EXEC(RTOS_ERR_INVALID_STATE,; );
370
}
371
}
372
}
373
374
/****************************************************************************************************//**
375
* HTTPsReq_Body()
376
*
377
* @brief Process Body received in HTTP request.
378
*
379
* @param p_instance Pointer to the instance.
380
*
381
* @param p_conn Pointer to the connection.
382
*
383
* @note (2) RFC #2616, Section 9 'Method Definitions' describes methods for HTTP/1.1:
384
* - (a) RFC #2616, Section 9.3 'GET' describes GET method:
385
*
386
* The GET method means retrieve whatever information (in the form of an
387
* entity) is identified by the Request-URI. If the Request-URI refers
388
* to a data-producing process, it is the produced data which shall be
389
* returned as the entity in the response and not the source text of the
390
* process, unless that text happens to be the output of the process.
391
*
392
* The semantics of the GET method change to a "conditional GET" if the
393
* request message includes an If-Modified-Since, If-Unmodified-Since,
394
* If-Match, If-None-Match, or If-Range header field. A conditional GET
395
* method requests that the entity be transferred only under the
396
* circumstances described by the conditional header field(s). The
397
* conditional GET method is intended to reduce unnecessary network
398
* usage by allowing cached entities to be refreshed without requiring
399
* multiple requests or transferring data already held by the client.
400
*
401
* The semantics of the GET method change to a "partial GET" if the
402
* request message includes a Range header field. A partial GET requests
403
* that only part of the entity be transferred, as described in section
404
* 14.35. The partial GET method is intended to reduce unnecessary
405
* network usage by allowing partially-retrieved entities to be
406
* completed without transferring data already held by the client.
407
*
408
* The response to a GET request is cacheable if and only if it meets
409
* the requirements for HTTP caching described in section 13.
410
*
411
* See section 15.1.3 for security considerations when used for forms.
412
*
413
* - (b) RFC #2616, Section 9.4 'HEAD' describes HEAD method:
414
*
415
* The HEAD method is identical to GET except that the server MUST NOT
416
* return a message-body in the response. The metainformation contained
417
* in the HTTP headers in response to a HEAD request SHOULD be identical
418
* to the information sent in response to a GET request. This method can
419
* be used for obtaining metainformation about the entity implied by the
420
* request without transferring the entity-body itself. This method is
421
* often used for testing hypertext links for validity, accessibility,
422
* and recent modification.
423
*
424
* - (c) RFC #2616, Section 9.5 'POST' describes POST method:
425
*
426
* The POST method is used to request that the origin server accept the entity
427
* enclosed in the request as a new subordinate of the resource identified by
428
* the Request-URI in the Request-Line. POST is designed to allow a uniform
429
* method to cover the following functions:
430
*
431
* - Annotation of existing resources;
432
* - Posting a message to a bulletin board, newsgroup, mailing list,
433
* or similar group of articles;
434
* - Providing a block of data, such as the result of submitting a
435
* form, to a data-handling process;
436
* - Extending a database through an append operation.
437
*
438
* The actual function performed by the POST method is determined by the server
439
* and is usually dependent on the Request-URI. The posted entity is subordinate
440
* to that URI in the same way that a file is subordinate to a directory
441
* containing it, a news article is subordinate to a newsgroup to which it is
442
* posted, or a record is subordinate to a database.
443
*
444
* The action performed by the POST method might not result in a resource that
445
* can be identified by a URI. In this case, either 200 (OK) or 204 (No Content)
446
* is the appropriate response status, depending on whether or not the response
447
* includes an entity that describes the result.
448
*
449
* If a resource has been created on the origin server, the response SHOULD be 201
450
* (Created) and contain an entity which describes the status of the request and
451
* refers to the new resource, and a Location header (see section 14.30).
452
*
453
* Responses to this method are not cacheable, unless the response includes
454
* appropriate Cache-Control or Expires header fields. However, the 303 (See Other)
455
* response can be used to direct the user agent to retrieve a cacheable resource.
456
*
457
* POST requests MUST obey the message transmission requirements set out in
458
* section 8.2.
459
*
460
* See section 15.1.3 for security considerations.
461
*******************************************************************************************************/
462
void HTTPsReq_Body(HTTPs_INSTANCE *p_instance,
463
HTTPs_CONN *p_conn)
464
{
465
const HTTPs_CFG *p_cfg;
466
HTTPs_INSTANCE_STATS *p_ctr_stats = DEF_NULL;
467
HTTPs_INSTANCE_ERRS *p_ctr_err = DEF_NULL;
468
CPU_SIZE_T data_len_rd;
469
CPU_BOOLEAN hook_continue;
470
CPU_BOOLEAN done;
471
CPU_BOOLEAN body_hook_def;
472
CPU_BOOLEAN req_flushed;
473
#if (HTTPs_CFG_FORM_EN == DEF_ENABLED)
474
CPU_BOOLEAN parse_done;
475
HTTPs_ERR local_err = HTTPs_ERR_NONE;
476
#endif
477
478
HTTPs_SET_PTR_STATS(p_ctr_stats, p_instance);
479
HTTPs_SET_PTR_ERRS(p_ctr_err, p_instance);
480
481
p_cfg = p_instance->CfgPtr;
482
483
done = DEF_NO;
484
while (done == DEF_NO) {
485
switch (p_conn->State) {
486
// ------------- PREPARE FOR BODY PARSING -------------
487
case HTTPs_CONN_STATE_REQ_BODY_INIT:
488
p_conn->ReqContentLenRxd = 0u; // Clear the length of data received variable.
489
490
// SET CONN STATE AND SOCKET STATE FOR BODY PARSING.
491
if (p_conn->ReqContentLen == 0) { // If all data received (no body) ...
492
// ... jump to response preparation.
493
p_conn->SockState = HTTPs_SOCK_STATE_NONE;
494
p_conn->State = HTTPs_CONN_STATE_REQ_READY_SIGNAL;
495
p_conn->RxBufLenRem = 0;
496
done = DEF_YES;
497
} else { // If a body is present in the request received:
498
switch (p_conn->Method) { // (1) Set the conn state for the parsing.
499
case HTTP_METHOD_GET:
500
p_conn->State = HTTPs_CONN_STATE_REQ_BODY_DATA;
501
HTTPs_STATS_INC(p_ctr_stats->Req_StatMethodGetProcessedCtr);
502
break;
503
504
case HTTP_METHOD_HEAD:
505
p_conn->State = HTTPs_CONN_STATE_REQ_BODY_DATA;
506
HTTPs_STATS_INC(p_ctr_stats->Req_StatMethodHeadProcessedCtr);
507
break;
508
509
case HTTP_METHOD_DELETE:
510
p_conn->State = HTTPs_CONN_STATE_REQ_BODY_DATA;
511
HTTPs_STATS_INC(p_ctr_stats->Req_StatMethodDeleteProcessedCtr);
512
break;
513
514
case HTTP_METHOD_PUT:
515
p_conn->State = HTTPs_CONN_STATE_REQ_BODY_DATA;
516
HTTPs_STATS_INC(p_ctr_stats->Req_StatMethodPutProcessedCtr);
517
break;
518
519
case HTTP_METHOD_POST:
520
// Check if the POST Content-Type matches with those ...
521
// ... the server core can parse.
522
#if (HTTPs_CFG_FORM_EN == DEF_ENABLED)
523
if (p_conn->ReqContentType == HTTP_CONTENT_TYPE_APP_FORM) {
524
p_conn->State = HTTPs_CONN_STATE_REQ_BODY_FORM_APP_PARSE;
525
} else if (p_conn->ReqContentType == HTTP_CONTENT_TYPE_MULTIPART_FORM) {
526
p_conn->State = HTTPs_CONN_STATE_REQ_BODY_FORM_MULTIPART_INIT;
527
} else {
528
p_conn->State = HTTPs_CONN_STATE_REQ_BODY_DATA;
529
}
530
#else
531
HTTPs_ERR_INC(p_ctr_err->Req_ErrBodyFormNotEn);
532
p_conn->State = HTTPs_CONN_STATE_REQ_BODY_DATA;
533
#endif
534
HTTPs_STATS_INC(p_ctr_stats->Req_StatMethodPostProcessedCtr);
535
break;
536
537
default:
538
HTTPs_STATS_INC(p_ctr_stats->Req_StatMethodUnsupportedProcessedCtr);
539
p_conn->ErrCode = HTTPs_ERR_REQ_METHOD_NOT_SUPPORTED;
540
p_conn->State = HTTPs_CONN_STATE_ERR_INTERNAL;
541
goto exit;
542
}
543
544
if (p_conn->RxBufLenRem == 0) { // (2) Set the socket state.
545
p_conn->SockState = HTTPs_SOCK_STATE_RX; // Need to Rx more data for parsing step.
546
done = DEF_YES;
547
} else {
548
p_conn->SockState = HTTPs_SOCK_STATE_NONE;
549
}
550
}
551
break;
552
553
// ----- NOTIFY UPPER APP THAT DATA IS AVAILABLE ------
554
case HTTPs_CONN_STATE_REQ_BODY_DATA:
555
body_hook_def = HTTPs_HOOK_DEFINED(p_cfg->HooksPtr, OnReqBodyRxHook);
556
// If the hook for the body is defined.
557
if (body_hook_def == DEF_TRUE) {
558
// Call the hook function.
559
hook_continue = p_cfg->HooksPtr->OnReqBodyRxHook(p_instance,
560
p_conn,
561
p_cfg->Hooks_CfgPtr,
562
p_conn->RxBufPtr,
563
p_conn->RxBufLenRem,
564
&data_len_rd);
565
566
if ((data_len_rd > p_conn->RxBufLenRem)
567
&& (p_conn->RxBufLenRem > 0) ) { // Fatal error.
568
p_conn->ErrCode = HTTPs_ERR_REQ_BODY_FAULT;
569
p_conn->State = HTTPs_CONN_STATE_ERR_INTERNAL;
570
goto exit;
571
}
572
573
// Update length of data consumed.
574
p_conn->RxBufLenRem -= data_len_rd;
575
p_conn->ReqContentLenRxd += data_len_rd;
576
p_conn->RxBufPtr += data_len_rd;
577
578
if (hook_continue == DEF_NO) { // Case when the App doesn't want to rx more data.
579
// While there is data to receive, flush it.
580
p_conn->State = HTTPs_CONN_STATE_REQ_BODY_FLUSH_DATA;
581
p_conn->SockState = HTTPs_SOCK_STATE_RX;
582
} else {
583
// If there is more data to read
584
if (p_conn->ReqContentLenRxd < p_conn->ReqContentLen) {
585
// Ask for more data.
586
p_conn->State = HTTPs_CONN_STATE_REQ_BODY_DATA;
587
p_conn->SockState = HTTPs_SOCK_STATE_RX;
588
} else {
589
// Otherwise, prepare the request response body.
590
p_conn->State = HTTPs_CONN_STATE_REQ_READY_SIGNAL;
591
p_conn->SockState = HTTPs_SOCK_STATE_NONE;
592
}
593
}
594
} else { // Case hook is not defined: flush data rx.
595
p_conn->State = HTTPs_CONN_STATE_REQ_BODY_FLUSH_DATA;
596
p_conn->SockState = HTTPs_SOCK_STATE_RX;
597
}
598
done = DEF_YES;
599
break;
600
601
// ----------- PARSE FORM RECEIVED IN POST ------------
602
case HTTPs_CONN_STATE_REQ_BODY_FORM_APP_PARSE:
603
case HTTPs_CONN_STATE_REQ_BODY_FORM_MULTIPART_INIT:
604
case HTTPs_CONN_STATE_REQ_BODY_FORM_MULTIPART_PARSE:
605
case HTTPs_CONN_STATE_REQ_BODY_FORM_MULTIPART_FILE_OPEN:
606
case HTTPs_CONN_STATE_REQ_BODY_FORM_MULTIPART_FILE_WR:
607
#if (HTTPs_CFG_FORM_EN == DEF_ENABLED)
608
parse_done = HTTPsReq_BodyForm(p_instance, p_conn, &local_err);
609
switch (local_err) {
610
case HTTPs_ERR_NONE:
611
if (parse_done == DEF_YES) {
612
p_conn->State = HTTPs_CONN_STATE_REQ_READY_SIGNAL;
613
p_conn->SockState = HTTPs_SOCK_STATE_NONE;
614
done = DEF_YES;
615
}
616
break;
617
618
case HTTPs_ERR_REQ_MORE_DATA_REQUIRED:
619
done = DEF_YES;
620
p_conn->SockState = HTTPs_SOCK_STATE_RX;
621
break;
622
623
default:
624
done = DEF_YES;
625
p_conn->ErrCode = local_err;
626
p_conn->State = HTTPs_CONN_STATE_ERR_INTERNAL;
627
p_conn->SockState = HTTPs_SOCK_STATE_NONE;
628
HTTPs_ERR_INC(p_ctr_err->Req_ErrBodyPostFormCtr);
629
break;
630
}
631
#else
632
HTTPs_ERR_INC(p_ctr_err->Req_ErrBodyFormNotEn);
633
p_conn->ErrCode = HTTPs_ERR_CFG_INVALID_FORM_EN;
634
p_conn->State = HTTPs_CONN_STATE_ERR_INTERNAL;
635
p_conn->SockState = HTTPs_SOCK_STATE_NONE;
636
#endif
637
break;
638
639
// ---------- FLUSH ALL REMAINING BODY DATA -----------
640
case HTTPs_CONN_STATE_REQ_BODY_FLUSH_DATA:
641
p_conn->ReqContentLenRxd += p_conn->RxBufLenRem;
642
p_conn->RxBufLenRem = 0;
643
644
if ((p_conn->ReqContentLen == 0)
645
|| (p_conn->ReqContentLenRxd >= p_conn->ReqContentLen)) {
646
// If there is no more data to receive. Process status.
647
req_flushed = DEF_BIT_IS_SET(p_conn->Flags, HTTPs_FLAG_REQ_FLUSH);
648
if (req_flushed == DEF_YES) {
649
p_conn->State = HTTPs_CONN_STATE_RESP_PREPARE;
650
} else {
651
p_conn->State = HTTPs_CONN_STATE_REQ_READY_SIGNAL;
652
}
653
p_conn->SockState = HTTPs_SOCK_STATE_NONE;
654
} else {
655
// While there is data to receive, flush it.
656
p_conn->State = HTTPs_CONN_STATE_REQ_BODY_FLUSH_DATA;
657
p_conn->SockState = HTTPs_SOCK_STATE_RX;
658
}
659
done = DEF_YES;
660
break;
661
662
default:
663
HTTPs_ERR_INC(p_ctr_err->Req_ErrBodyStateUnknownCtr);
664
p_conn->ErrCode = HTTPs_ERR_STATE_UNKNOWN;
665
p_conn->State = HTTPs_CONN_STATE_ERR_INTERNAL;
666
RTOS_CRITICAL_FAIL_EXEC(RTOS_ERR_INVALID_STATE,; );
667
}
668
}
669
670
exit:
671
return;
672
}
673
674
/****************************************************************************************************//**
675
* HTTPsReq_RdySignal()
676
*
677
* @brief Signal the upper application that the request was received completely and that it CAN
678
* start the request processing.
679
*
680
* @param p_instance Pointer to the instance.
681
*
682
* @param p_conn Pointer to the connection.
683
*
684
* @return DEF_YES, if upper application has finish the request processing.
685
* DEF_NO, otherwise.
686
*
687
* @note (1) If the request processing by the application is not completed the poll hook will be called
688
* until it's done.
689
*******************************************************************************************************/
690
CPU_BOOLEAN HTTPsReq_RdySignal(HTTPs_INSTANCE *p_instance,
691
HTTPs_CONN *p_conn)
692
{
693
const HTTPs_CFG *p_cfg = p_instance->CfgPtr;
694
HTTPs_KEY_VAL *p_key_val = DEF_NULL;
695
CPU_BOOLEAN hook_def = DEF_NO;
696
CPU_BOOLEAN process_done = DEF_NO;
697
698
#if (HTTPs_CFG_FORM_EN == DEF_ENABLED)
699
p_key_val = p_conn->FormDataListPtr;
700
#endif
701
702
switch (p_conn->State) {
703
// ------------ POST DATA RX TO USER APP --------------
704
case HTTPs_CONN_STATE_REQ_READY_SIGNAL:
705
hook_def = HTTPs_HOOK_DEFINED(p_cfg->HooksPtr, OnReqRdySignalHook);
706
if (hook_def == DEF_YES) {
707
// Callback fnct process data.
708
process_done = p_cfg->HooksPtr->OnReqRdySignalHook(p_instance,
709
p_conn,
710
p_cfg->Hooks_CfgPtr,
711
(const HTTPs_KEY_VAL *)p_key_val);
712
713
if (process_done != DEF_YES) {
714
p_conn->State = HTTPs_CONN_STATE_REQ_READY_POLL;
715
}
716
} else {
717
process_done = DEF_YES;
718
}
719
break;
720
721
// ----------- WAIT END OF DATA PROCESSING ------------
722
case HTTPs_CONN_STATE_REQ_READY_POLL:
723
hook_def = HTTPs_HOOK_DEFINED(p_cfg->HooksPtr, OnReqRdyPollHook);
724
if (hook_def == DEF_YES) {
725
// Wait until data processing is completed.
726
process_done = p_cfg->HooksPtr->OnReqRdyPollHook(p_instance,
727
p_conn,
728
p_cfg->Hooks_CfgPtr);
729
} else {
730
process_done = DEF_YES;
731
}
732
break;
733
734
default:
735
process_done = DEF_YES;
736
p_conn->ErrCode = HTTPs_ERR_STATE_UNKNOWN;
737
p_conn->State = HTTPs_CONN_STATE_ERR_INTERNAL;
738
RTOS_CRITICAL_FAIL_EXEC(RTOS_ERR_INVALID_STATE, process_done);
739
}
740
741
return (process_done);
742
}
743
744
/********************************************************************************************************
745
********************************************************************************************************
746
* LOCAL FUNCTIONS
747
********************************************************************************************************
748
*******************************************************************************************************/
749
750
/****************************************************************************************************//**
751
* HTTPsReq_MethodParse()
752
*
753
* @brief Parse request Method
754
*
755
* @param p_instance Pointer to the instance.
756
*
757
* @param p_conn Pointer to the connection.
758
*
759
* @param p_err Pointer to variable that will receive the return error code from this function.
760
*
761
* @note (2) RFC #2616, Section 5.1.1 'Method' defines request line methods:
762
* The Method token indicates the method to be performed on the resource identified by the
763
* Request-URI. The method is case-sensitive.
764
*
765
* Method = "OPTIONS" ; Section 9.2
766
* | "GET" ; Section 9.3
767
* | "HEAD" ; Section 9.4
768
* | "POST" ; Section 9.5
769
* | "PUT" ; Section 9.6
770
* | "DELETE" ; Section 9.7
771
* | "TRACE" ; Section 9.8
772
* | "CONNECT" ; Section 9.9
773
* | extension-method
774
* extension-method = token
775
*
776
* The list of methods allowed by a resource can be specified in an Allow header field
777
* (section 14.7). The return code of the response always notifies the client whether a
778
* method is currently allowed on a resource, since the set of allowed methods can change
779
* dynamically. An origin server SHOULD return the status code 405 (Method Not Allowed)
780
* if the method is known by the origin server but not allowed for the requested resource,
781
* and 501 (Not Implemented) if the method is unrecognized or not implemented by the origin
782
* server. The methods GET and HEAD MUST be supported by all general-purpose servers. All
783
* other methods are OPTIONAL; however, if the above methods are implemented, they MUST be
784
* implemented with the same semantics as those specified in section 9.
785
*******************************************************************************************************/
786
static void HTTPsReq_MethodParse(HTTPs_INSTANCE *p_instance,
787
HTTPs_CONN *p_conn,
788
HTTPs_ERR *p_err)
789
{
790
CPU_CHAR *p_request_method_start;
791
CPU_CHAR *p_request_method_end;
792
CPU_SIZE_T len;
793
HTTPs_INSTANCE_STATS *p_ctr_stats = DEF_NULL;
794
CPU_INT32U method;
795
796
PP_UNUSED_PARAM(p_instance);
797
HTTPs_SET_PTR_STATS(p_ctr_stats, p_instance);
798
799
len = p_conn->RxBufLenRem;
800
801
if (len <= sizeof(HTTP_STR_METHOD_GET)) { // Check minimum length of RxBuf.
802
*p_err = HTTPs_ERR_REQ_FORMAT_INVALID;
803
return;
804
}
805
// Move the start ptr to the first meaningful char.
806
p_request_method_start = HTTP_StrGraphSrchFirst(p_conn->RxBufPtr, len);
807
if (p_request_method_start == DEF_NULL) {
808
*p_err = HTTPs_ERR_REQ_FORMAT_INVALID;
809
return;
810
}
811
len -= p_request_method_start - p_conn->RxBufPtr;
812
// Find the end of method string.
813
p_request_method_end = Str_Char_N(p_request_method_start, len, ASCII_CHAR_SPACE);
814
if (p_request_method_end == DEF_NULL) {
815
*p_err = HTTPs_ERR_REQ_FORMAT_INVALID;
816
return;
817
}
818
len = p_request_method_end - p_request_method_start;
819
// Try to match the Method str received.
820
method = HTTP_Dict_KeyGet(HTTP_Dict_ReqMethod,
821
HTTP_Dict_ReqMethodSize,
822
p_request_method_start,
823
DEF_YES,
824
len);
825
// Validate the DictionaryKey search results
826
if (method == HTTP_DICT_KEY_INVALID) {
827
p_conn->Method = HTTP_METHOD_UNKNOWN;
828
} else {
829
p_conn->Method = (HTTP_METHOD)method;
830
}
831
832
switch (p_conn->Method) {
833
case HTTP_METHOD_GET:
834
LOG_VRB(("HTTPs - SockID: ", (u)p_conn->SockID, " - Method = GET"));
835
p_conn->RespBodyDataType = HTTPs_BODY_DATA_TYPE_FILE;
836
HTTPs_STATS_INC(p_ctr_stats->Req_StatMethodGetRxdCtr);
837
break;
838
839
case HTTP_METHOD_HEAD:
840
LOG_VRB(("HTTPs - SockID: ", (u)p_conn->SockID, " - Method = HEAD"));
841
p_conn->RespBodyDataType = HTTPs_BODY_DATA_TYPE_FILE;
842
HTTPs_STATS_INC(p_ctr_stats->Req_StatMethodHeadRxdCtr);
843
break;
844
845
case HTTP_METHOD_POST:
846
LOG_VRB(("HTTPs - SockID: ", (u)p_conn->SockID, " - Method = POST"));
847
p_conn->RespBodyDataType = HTTPs_BODY_DATA_TYPE_NONE;
848
HTTPs_STATS_INC(p_ctr_stats->Req_StatMethodPostRxdCtr);
849
break;
850
851
case HTTP_METHOD_DELETE:
852
LOG_VRB(("HTTPs - SockID: ", (u)p_conn->SockID, " - Method = DELETE"));
853
p_conn->RespBodyDataType = HTTPs_BODY_DATA_TYPE_NONE;
854
HTTPs_STATS_INC(p_ctr_stats->Req_StatMethodDeleteRxdCtr);
855
break;
856
857
case HTTP_METHOD_PUT:
858
LOG_VRB(("HTTPs - SockID: ", (u)p_conn->SockID, " - Method = PUT"));
859
p_conn->RespBodyDataType = HTTPs_BODY_DATA_TYPE_NONE;
860
HTTPs_STATS_INC(p_ctr_stats->Req_StatMethodPutRxdCtr);
861
break;
862
863
case HTTP_METHOD_TRACE:
864
case HTTP_METHOD_CONNECT:
865
case HTTP_METHOD_UNKNOWN:
866
default:
867
LOG_VRB(("HTTPs - SockID: ", (u)p_conn->SockID, " - Method = Unsupported"));
868
HTTPs_STATS_INC(p_ctr_stats->Req_StatMethodUnsupportedRxdCtr);
869
*p_err = HTTPs_ERR_REQ_METHOD_NOT_SUPPORTED;
870
return;
871
}
872
// Update the RxBuf ptr.
873
p_conn->RxBufLenRem -= len;
874
p_conn->RxBufPtr = p_request_method_end;
875
876
*p_err = HTTPs_ERR_NONE;
877
}
878
879
/****************************************************************************************************//**
880
* HTTPsReq_URI_Parse()
881
*
882
* @brief Parse request URI and check for potential query string.
883
*
884
* @param p_instance Pointer to the instance.
885
*
886
* @param ---------- Argument validated in HTTPs_InstanceStart().
887
*
888
* @param p_conn Pointer to the connection.
889
*
890
* @param ----- Argument validated in HTTPs_InstanceStart().
891
*
892
* @param p_err Pointer to variable that will receive the return error code from this function.
893
*
894
* @return DEF_YES, if potential query string is found.
895
* DEF_NO, if NO potential query string is found.
896
*
897
* @note (1) The Request-URI is a Uniform Resource Identifier (section 3.2) and identifies the resource
898
* upon which to apply the request.
899
*
900
* Request-URI = "*" | absoluteURI | abs_path | authority
901
*
902
* - (a) The asterisk "*" means that the request does not apply to a particular resource, but to
903
* the server itself, and is only allowed when the method used does not necessarily apply
904
* to a resource. One example would be
905
*
906
* OPTIONS * HTTP/1.1
907
*
908
* - (b) The absoluteURI form is REQUIRED when the request is being made to a proxy. The proxy is
909
* requested to forward the request or service it from a valid cache, and return the response.
910
* Note that the proxy MAY forward the request on to another proxy or directly to the server
911
* specified by the absoluteURI. In order to avoid request loops, a proxy MUST be able to
912
* recognize all of its server names, including any aliases, local variations, and the numeric
913
* IP address. An example Request-Line would be:
914
*
915
* GET http://www.w3.org/pub/WWW/TheProject.html HTTP/1.1
916
*
917
* To allow for transition to absoluteURIs in all requests in future versions of HTTP, all
918
* HTTP/1.1 servers MUST accept the absoluteURI form in requests, even though HTTP/1.1 clients
919
* will only generate them in requests to proxies.
920
*
921
* - (c) The authority form is only used by the CONNECT method (section 9.9).
922
*
923
* - (d) The most common form of Request-URI is that used to identify a resource on an origin server or
924
* gateway. In this case the absolute path of the URI MUST be transmitted (see section 3.2.1,
925
* abs_path) as the Request-URI, and the network location of the URI (authority) MUST be transmitted
926
* in a Host header field. For example, a client wishing to retrieve the resource above directly
927
* from the origin server would create a TCP connection to port 80 of the host "www.w3.org" and send
928
* the lines:
929
*
930
* GET /pub/WWW/TheProject.html HTTP/1.1
931
* Host: www.w3.org
932
*
933
* followed by the remainder of the Request. Note that the absolute path cannot be empty; if none
934
* is present in the original URI, it MUST be given as "/" (the server root).
935
*
936
* - (e) The Request-URI is transmitted in the format specified in section 3.2.1. If the Request-URI is
937
* encoded using the "% HEX HEX" encoding [42], the origin server MUST decode the Request-URI in
938
* order to properly interpret the request. Servers SHOULD respond to invalid Request-URIs with an
939
* appropriate status code.
940
*******************************************************************************************************/
941
static CPU_BOOLEAN HTTPsReq_URI_Parse(HTTPs_INSTANCE *p_instance,
942
HTTPs_CONN *p_conn,
943
HTTPs_ERR *p_err)
944
{
945
const HTTPs_CFG *p_cfg = p_instance->CfgPtr;;
946
CPU_CHAR *p_request_uri_start = DEF_NULL;
947
CPU_CHAR *p_request_uri_end = DEF_NULL;
948
CPU_CHAR *p_request_uri_separator = DEF_NULL;
949
CPU_CHAR *p_str = DEF_NULL;
950
CPU_INT32U len = p_conn->RxBufLenRem;;
951
CPU_SIZE_T len_decoded = 0u;
952
CPU_BOOLEAN is_query_found = DEF_NO;
953
954
// Move the start ptr to the first meaningful char.
955
p_request_uri_start = HTTP_StrGraphSrchFirst(p_conn->RxBufPtr, len);
956
if (p_request_uri_start == DEF_NULL) {
957
*p_err = HTTPs_ERR_REQ_FORMAT_INVALID;
958
return (is_query_found);
959
}
960
// Find the end of the URI including the potential...
961
// ...query str.
962
len -= p_request_uri_start - p_conn->RxBufPtr;
963
p_request_uri_end = Str_Char_N(p_request_uri_start, len, ASCII_CHAR_SPACE);
964
if (p_request_uri_end != DEF_NULL) {
965
len = p_request_uri_end - p_request_uri_start; // Recalculate the len to narrow the search.
966
}
967
// Try to find a '?' for query string.
968
p_request_uri_separator = Str_Char_N(p_request_uri_start, len, ASCII_CHAR_QUESTION_MARK);
969
if (p_request_uri_separator == DEF_NULL) { // If no query string or a full URI is found...
970
if (p_request_uri_end == DEF_NULL) {
971
if (p_conn->RxBufPtr != p_conn->BufPtr) { // ...and if the buffer is not full...
972
// ... get more data.
973
*p_err = HTTPs_ERR_REQ_MORE_DATA_REQUIRED;
974
} else {
975
// ... but if the buffer is full, generate an error.
976
*p_err = HTTPs_ERR_REQ_FORMAT_INVALID;
977
}
978
return (is_query_found);
979
}
980
} else {
981
is_query_found = DEF_YES;
982
len = p_request_uri_separator - p_request_uri_start;
983
}
984
985
if (len > p_conn->PathLenMax) { // If unable to store req'd URI.
986
*p_err = HTTPs_ERR_REQ_URI_LEN; // Resp with internal err page.
987
return (is_query_found);
988
}
989
990
p_request_uri_start[len] = ASCII_CHAR_NULL; // Replace the char at the end of the URI by NULL.
991
992
if (len > 1) { // Req'd URI is not the default.
993
// Copy req'd URI.
994
len_decoded = len;
995
996
HTTP_URL_DecodeStr(p_request_uri_start,
997
p_conn->PathPtr,
998
&len_decoded);
999
1000
p_conn->PathPtr[len_decoded] = ASCII_CHAR_NULL;
1001
} else { // Default page req'd.
1002
p_str = p_conn->PathPtr;
1003
1004
if ((p_cfg->DfltResourceNamePtr[0] != HTTPs_PATH_SEP_CHAR_DFLT)
1005
&& (p_cfg->DfltResourceNamePtr[0] != ASCII_CHAR_REVERSE_SOLIDUS)) {
1006
p_str[0] = HTTPs_PATH_SEP_CHAR_DFLT;
1007
p_str++;
1008
}
1009
// Copy dflt file path.
1010
Str_Copy_N(p_str,
1011
p_cfg->DfltResourceNamePtr,
1012
p_conn->PathLenMax);
1013
1014
Str_Char_Replace_N(p_conn->PathPtr,
1015
ASCII_CHAR_REVERSE_SOLIDUS,
1016
HTTPs_PATH_SEP_CHAR_DFLT,
1017
p_conn->PathLenMax);
1018
}
1019
// Update rem len avail in the rx buf.
1020
p_conn->RxBufLenRem -= (&p_request_uri_start[len] - p_conn->RxBufPtr) + 1;
1021
p_conn->RxBufPtr = &p_request_uri_start[len] + 1;
1022
1023
LOG_VRB(("HTTPs - SockId: ", (u)p_conn->SockID, "\r\n URI =", (s)p_conn->PathPtr));
1024
1025
*p_err = HTTPs_ERR_NONE;
1026
1027
return (is_query_found);
1028
}
1029
1030
/****************************************************************************************************//**
1031
* HTTPsReq_QueryStrParse()
1032
*
1033
* @brief Parse request query string.
1034
*
1035
* @param p_instance Pointer to the instance.
1036
*
1037
* @param _conn Pointer to the connection.
1038
*
1039
* @param _err Pointer to variable that will receive the return error code from this function.
1040
*
1041
* @note (1) RFC #3986, Section 3.4 "Query" state:
1042
*
1043
* The query component contains non-hierarchical data that, along with
1044
* data in the path component (Section 3.3), serves to identify a
1045
* resource within the scope of the URI's scheme and naming authority
1046
* (if any). The query component is indicated by the first question
1047
* mark ("?") character and terminated by a number sign ("#") character
1048
* or by the end of the URI.
1049
*
1050
* - (2) W3C Recommendations :
1051
*
1052
* http://www.w3.org/Addressing/URL/4_URI_Recommentations.html
1053
*
1054
* - (2) Each query must be Key-Value Pair separated by a equals sign ('=').
1055
*
1056
* - (3) Control names and values are escaped. Space characters are replaced by `+', and then
1057
* reserved characters are escaped as described in [RFC1738], section 2.2: Non-alphanumeric
1058
* characters are replaced by '%HH', a percent sign and two hexadecimal digits representing
1059
* the ASCII code of the character. Line breaks are represented as "CR LF" pairs
1060
* (i.e., '%0D%0A').
1061
*******************************************************************************************************/
1062
static void HTTPsReq_QueryStrParse(HTTPs_INSTANCE *p_instance,
1063
HTTPs_CONN *p_conn,
1064
HTTPs_ERR *p_err)
1065
{
1066
CPU_CHAR *p_req_line_end = DEF_NULL;
1067
CPU_CHAR *p_query_str_end = DEF_NULL;
1068
CPU_CHAR *p_field_start = DEF_NULL;
1069
CPU_CHAR *p_field_end = DEF_NULL;
1070
CPU_INT32U len = p_conn->RxBufLenRem;
1071
CPU_INT32U len_rd = 0;
1072
CPU_INT32U key_val_pair_len = 0;
1073
CPU_BOOLEAN done = DEF_NO;
1074
#if (HTTPs_CFG_QUERY_STR_EN == DEF_ENABLED)
1075
CPU_BOOLEAN success = DEF_NO;
1076
#endif
1077
1078
#if (HTTPs_CFG_QUERY_STR_EN == DEF_DISABLED)
1079
PP_UNUSED_PARAM(p_instance);
1080
#endif
1081
// Check for the end of the request line.
1082
p_req_line_end = Str_Str_N(p_conn->RxBufPtr, STR_CR_LF, len);
1083
if (p_req_line_end != DEF_NULL) {
1084
len = p_req_line_end - p_conn->RxBufPtr;
1085
}
1086
1087
// Check for the end of the query string.
1088
p_query_str_end = Str_Char_N(p_conn->RxBufPtr, len, ASCII_CHAR_SPACE);
1089
if (p_query_str_end != DEF_NULL) {
1090
len = p_query_str_end - p_conn->RxBufPtr + 1; // If found, set the query length.
1091
}
1092
1093
p_field_start = p_conn->RxBufPtr;
1094
1095
while (done == DEF_NO) {
1096
// Search for the query string char separator (&).
1097
p_field_end = Str_Char_N(p_field_start, len, ASCII_CHAR_AMPERSAND);
1098
if (p_field_end == DEF_NULL) { // If not found, check if it's the last query string.
1099
if (p_query_str_end == DEF_NULL) {
1100
if (len == p_conn->BufLen) {
1101
*p_err = HTTPs_ERR_CFG_INVALID_BUF_LEN;
1102
} else {
1103
*p_err = HTTPs_ERR_REQ_MORE_DATA_REQUIRED;
1104
}
1105
goto exit_update;
1106
} else {
1107
done = DEF_YES; // Last field of query string.
1108
p_field_end = p_query_str_end;
1109
}
1110
}
1111
1112
// Get the length of the key-value pair found.
1113
key_val_pair_len = p_field_end - p_field_start;
1114
if (key_val_pair_len == 0u) { // In the case it's null, the query has been fully ...
1115
*p_err = HTTPs_ERR_NONE; // ...parsed and it has finished by a '&'.
1116
goto exit_update;
1117
}
1118
1119
#if (HTTPs_CFG_QUERY_STR_EN == DEF_ENABLED)
1120
success = HTTPsReq_QueryStrKeyValBlkAdd(p_instance,
1121
p_conn,
1122
p_field_start,
1123
key_val_pair_len,
1124
p_err);
1125
if (success == DEF_FAIL) {
1126
goto exit_update;
1127
}
1128
#endif
1129
1130
p_field_start += (key_val_pair_len + 1);
1131
len -= (key_val_pair_len + 1);
1132
len_rd += (key_val_pair_len + 1);
1133
}
1134
1135
*p_err = HTTPs_ERR_NONE;
1136
1137
exit_update:
1138
p_conn->RxBufLenRem -= len_rd;
1139
p_conn->RxBufPtr += len_rd;
1140
1141
return;
1142
}
1143
1144
/****************************************************************************************************//**
1145
* HTTPsReq_QueryStrKeyValBlkAdd()
1146
*
1147
* @brief Add query field received in the Query String to the query list.
1148
*
1149
* @param p_instance Pointer to the instance.
1150
*
1151
* @param p_conn Pointer to the connection.
1152
*
1153
* @param p_str Pointer to start of query field string.
1154
*
1155
* @param str_len Length of query field.
1156
*
1157
* @param p_err Pointer to variable that will receive the return error code from this function.
1158
*
1159
* @return DEF_OK, if query field successfully added to the list.
1160
* DEF_FAIL, otherwise.
1161
*******************************************************************************************************/
1162
#if (HTTPs_CFG_QUERY_STR_EN == DEF_ENABLED)
1163
static CPU_BOOLEAN HTTPsReq_QueryStrKeyValBlkAdd(HTTPs_INSTANCE *p_instance,
1164
HTTPs_CONN *p_conn,
1165
CPU_CHAR *p_str,
1166
CPU_SIZE_T str_len,
1167
HTTPs_ERR *p_err)
1168
{
1169
const HTTPs_CFG *p_cfg;
1170
HTTPs_KEY_VAL *p_key_val;
1171
CPU_BOOLEAN result;
1172
RTOS_ERR local_err;
1173
1174
RTOS_ERR_SET(local_err, RTOS_ERR_NONE);
1175
1176
p_cfg = p_instance->CfgPtr;
1177
1178
if (p_cfg->QueryStrCfgPtr != DEF_NULL) {
1179
if (p_cfg->QueryStrCfgPtr->NbrPerConnMax != LIB_MEM_BLK_QTY_UNLIMITED) {
1180
if (p_conn->QueryStrBlkAcquiredCtr >= p_cfg->QueryStrCfgPtr->NbrPerConnMax) {
1181
*p_err = HTTPs_ERR_KEY_VAL_CFG_POOL_SIZE_INV;
1182
return (DEF_FAIL);
1183
}
1184
}
1185
1186
p_key_val = HTTPsMem_QueryStrKeyValBlkGet(p_instance, // Acquire Key-Value block.
1187
p_conn,
1188
&local_err);
1189
if (p_key_val == DEF_NULL) { // If no Key-Value block available.
1190
*p_err = HTTPs_ERR_QUERY_STR_POOL_GET;
1191
return (DEF_FAIL);
1192
}
1193
1194
result = HTTPsReq_URL_EncodeStrParse(p_instance,
1195
p_conn,
1196
p_key_val,
1197
DEF_YES,
1198
p_str,
1199
str_len);
1200
if (result == DEF_FAIL) {
1201
*p_err = HTTPs_ERR_QUERY_STR_PARSE_FAULT;
1202
return (DEF_FAIL);
1203
}
1204
1205
if (p_conn->QueryStrListPtr == DEF_NULL) {
1206
p_key_val->NextPtr = DEF_NULL;
1207
} else {
1208
p_key_val->NextPtr = p_conn->QueryStrListPtr;
1209
}
1210
1211
p_conn->QueryStrListPtr = p_key_val;
1212
}
1213
1214
*p_err = HTTPs_ERR_NONE;
1215
1216
return (DEF_OK);
1217
}
1218
#endif
1219
1220
/****************************************************************************************************//**
1221
* HTTPsReq_ProtocolVerParse()
1222
*
1223
* @brief Parse request protocol version
1224
*
1225
* @param p_instance Pointer to the instance.
1226
*
1227
* @param p_conn Pointer to the connection.
1228
*
1229
* @param p_err Pointer to variable that will receive the return error code from this function.
1230
*
1231
* @note (1) At the time of implementing this HTTP server version, only the following HTTP version
1232
* are known:
1233
*
1234
* - (a) HTTP/0.9
1235
* - (b) HTTP/1.0
1236
* - (c) HTTP/1.1
1237
*
1238
* @note (2) RFC #2616, Section 19.6 "Compatibility with Previous Versions" state:
1239
*
1240
* It is beyond the scope of a protocol specification to mandate
1241
* compliance with previous versions. HTTP/1.1 was deliberately
1242
* designed, however, to make supporting previous versions easy. It is
1243
* worth noting that, at the time of composing this specification
1244
* (1996), we would expect commercial HTTP/1.1 servers to:
1245
*
1246
* - recognize the format of the Request-Line for HTTP/0.9, 1.0, and
1247
* 1.1 requests;
1248
* - understand any valid request in the format of HTTP/0.9, 1.0, or
1249
* 1.1;
1250
* And we would expect HTTP/1.1 clients to:
1251
*
1252
* - recognize the format of the Status-Line for HTTP/1.0 and 1.1
1253
* responses;
1254
*
1255
* - understand any valid response in the format of HTTP/0.9, 1.0, or
1256
* 1.1.
1257
*
1258
* For most implementations of HTTP/1.0, each connection is established
1259
* by the client prior to the request and closed by the server after
1260
* sending the response. Some implementations implement the Keep-Alive
1261
* version of persistent connections described in section 19.7.1 of RFC
1262
* 2068 [33].
1263
*******************************************************************************************************/
1264
static void HTTPsReq_ProtocolVerParse(HTTPs_INSTANCE *p_instance,
1265
HTTPs_CONN *p_conn,
1266
HTTPs_ERR *p_err)
1267
{
1268
#if (HTTPs_CFG_PERSISTENT_CONN_EN == DEF_ENABLED)
1269
const HTTPs_CFG *p_cfg = p_instance->CfgPtr;
1270
#endif
1271
CPU_CHAR *p_protocol_ver_start;
1272
CPU_CHAR *p_protocol_ver_end;
1273
CPU_INT32U len;
1274
CPU_INT32U protocol_ver;
1275
HTTPs_INSTANCE_STATS *p_ctr_stats = DEF_NULL;
1276
1277
#if (HTTPs_CFG_PERSISTENT_CONN_EN == DEF_DISABLED)
1278
PP_UNUSED_PARAM(p_instance);
1279
#endif
1280
HTTPs_SET_PTR_STATS(p_ctr_stats, p_instance);
1281
1282
len = p_conn->RxBufLenRem;
1283
if (len == 0) { // If there's no more remaining char and the last...
1284
*p_err = HTTPs_ERR_REQ_MORE_DATA_REQUIRED;
1285
return;
1286
}
1287
// Move the pointer to the next meaningful char.
1288
p_protocol_ver_start = HTTP_StrGraphSrchFirst(p_conn->RxBufPtr, len);
1289
if (p_protocol_ver_start == DEF_NULL) {
1290
*p_err = HTTPs_ERR_REQ_FORMAT_INVALID;
1291
return;
1292
}
1293
// Find the end of the request line.
1294
p_protocol_ver_end = Str_Str_N(p_protocol_ver_start, STR_CR_LF, len);
1295
if (p_protocol_ver_end == DEF_NULL) { // If not found, check to get more data.
1296
if (p_conn->RxBufPtr != p_conn->BufPtr) {
1297
*p_err = HTTPs_ERR_REQ_MORE_DATA_REQUIRED;
1298
} else {
1299
*p_err = HTTPs_ERR_REQ_FORMAT_INVALID;
1300
}
1301
return;
1302
}
1303
1304
len = p_protocol_ver_end - p_protocol_ver_start;
1305
// Try to match the Protocol version string.
1306
protocol_ver = HTTP_Dict_KeyGet(HTTP_Dict_ProtocolVer,
1307
HTTP_Dict_ProtocolVerSize,
1308
p_protocol_ver_start,
1309
DEF_YES,
1310
len);
1311
1312
// Validate the DictionaryKey search results
1313
if (protocol_ver == HTTP_DICT_KEY_INVALID) {
1314
p_conn->ProtocolVer = HTTP_PROTOCOL_VER_UNKNOWN;
1315
} else {
1316
p_conn->ProtocolVer = (HTTP_PROTOCOL_VER)protocol_ver;
1317
}
1318
1319
switch (p_conn->ProtocolVer) {
1320
case HTTP_PROTOCOL_VER_0_9:
1321
HTTPs_STATS_INC(p_ctr_stats->Req_StatProtocolVer0_9Ctr);
1322
break;
1323
1324
case HTTP_PROTOCOL_VER_1_0:
1325
HTTPs_STATS_INC(p_ctr_stats->Req_StatProtocolVer1_0Ctr);
1326
break;
1327
1328
case HTTP_PROTOCOL_VER_1_1:
1329
#if (HTTPs_CFG_PERSISTENT_CONN_EN == DEF_ENABLED)
1330
if (p_cfg->ConnPersistentEn == DEF_ENABLED) {
1331
DEF_BIT_SET(p_conn->Flags, HTTPs_FLAG_CONN_PERSISTENT);
1332
}
1333
#endif
1334
HTTPs_STATS_INC(p_ctr_stats->Req_StatProtocolVer1_1Ctr);
1335
break;
1336
1337
case HTTP_PROTOCOL_VER_UNKNOWN:
1338
default:
1339
HTTPs_STATS_INC(p_ctr_stats->Req_StatProtocolVerUnsupportedCtr);
1340
p_conn->ProtocolVer = HTTP_PROTOCOL_VER_1_1;
1341
*p_err = HTTPs_ERR_REQ_PROTOCOL_VER_NOT_SUPPORTED;
1342
return;
1343
}
1344
// Update the RxBuf ptr.
1345
p_conn->RxBufLenRem -= (p_protocol_ver_end - p_conn->RxBufPtr) + 2;
1346
p_conn->RxBufPtr = p_protocol_ver_end + 2;
1347
1348
*p_err = HTTPs_ERR_NONE;
1349
}
1350
1351
/****************************************************************************************************//**
1352
* HTTPsReq_HdrParse()
1353
*
1354
* @brief (1) Parse request headers:
1355
* - (a) Analyze fields contained in the field header section
1356
* - (b) Store field value:
1357
* - (1) Store Content type field
1358
* - (a) Content type application
1359
* - (b) Content type multipart
1360
* - (2) Content length*
1361
* - (3) Host
1362
* - (c) Update receive connection parameters
1363
*
1364
* @param p_instance Pointer to the instance.
1365
*
1366
* @param p_conn Pointer to the connection.
1367
*
1368
* @param p_err Pointer to variable that will receive the return error code from this function.
1369
*
1370
* @note (2) RFC #2616, Section "5.3 Request Header Fields" describe the request header field definitions
1371
*
1372
* - (a) The request-header fields allow the client to pass additional information about the
1373
* request, and about the client itself, to the server. These fields act as request
1374
* modifiers, with semantics equivalent to the parameters on a programming language
1375
* method invocation.
1376
*
1377
* request-header = Accept
1378
* | Accept-Charset
1379
* | Accept-Encoding
1380
* | Accept-Language
1381
* | Authorization
1382
* | Expect
1383
* | From
1384
* | Host
1385
* | If-Match
1386
* | If-Modified-Since
1387
* | If-None-Match
1388
* | If-Range
1389
* | If-Unmodified-Since
1390
* | Max-Forwards
1391
* | Proxy-Authorization
1392
* | Range
1393
* | Referer
1394
* | TE
1395
* | User-Agent
1396
*
1397
* Request-header field names can be extended reliably only in combination with a change
1398
* in the protocol version. However, new or experimental header fields MAY be given the
1399
* semantics of request- header fields if all parties in the communication recognize
1400
* them to be request-header fields. Unrecognized header fields are treated as
1401
* entity-header fields.
1402
*
1403
* @note (3) HTML 4.01 Specification section "17.13 Form submission" explain how user agents submit
1404
* form data to form processing agents:
1405
*
1406
* - (a) The content type "application/x-www-form-urlencoded" is the default content type.
1407
*
1408
* - (b) The content type "multipart/form-data" should be used for submitting forms that contain files,
1409
* non-ASCII data, and binary data.
1410
*
1411
* The content "multipart/form-data" follows the rules of all multipart MIME data streams as
1412
* outlined in [RFC2045]. The definition of "multipart/form-data" is available at the [IANA]
1413
* registry.
1414
*
1415
* If the user selected a second (image) file "file2.gif", the user agent might construct the parts as follows:
1416
*
1417
* Content-Type: multipart/form-data; boundary=AaB03x
1418
*******************************************************************************************************/
1419
static void HTTPsReq_HdrParse(HTTPs_INSTANCE *p_instance,
1420
HTTPs_CONN *p_conn,
1421
HTTPs_ERR *p_err)
1422
{
1423
CPU_CHAR *p_field;
1424
CPU_CHAR *p_field_end;
1425
CPU_CHAR *p_val;
1426
CPU_INT32U field_key;
1427
HTTP_HDR_FIELD field;
1428
CPU_INT16U len;
1429
HTTPs_INSTANCE_STATS *p_ctr_stats = DEF_NULL;
1430
#if (HTTPs_CFG_HDR_RX_EN == DEF_ENABLED)
1431
CPU_CHAR *p_str;
1432
HTTP_DICT *p_field_dict_entry;
1433
HTTPs_HDR_BLK *p_req_hdr_blk;
1434
HTTPs_HDR_VAL_TYPE val_type;
1435
CPU_BOOLEAN keep;
1436
#endif
1437
#if (((HTTPs_CFG_FORM_EN == DEF_ENABLED) \
1438
&& (HTTPs_CFG_FORM_MULTIPART_EN == DEF_ENABLED)) \
1439
|| (HTTPs_CFG_HDR_RX_EN == DEF_ENABLED))
1440
HTTPs_INSTANCE_ERRS *p_ctr_errs = DEF_NULL;
1441
#endif
1442
1443
#if ((HTTPs_CFG_FORM_EN == DEF_ENABLED) \
1444
&& (HTTPs_CFG_FORM_MULTIPART_EN == DEF_ENABLED))
1445
const HTTP_DICT *p_dictionary;
1446
#endif
1447
#if ((HTTPs_CFG_HDR_RX_EN == DEF_ENABLED) \
1448
|| (HTTPs_CFG_ABSOLUTE_URI_EN == DEF_ENABLED) \
1449
|| ((HTTPs_CFG_FORM_EN == DEF_ENABLED) \
1450
&& (HTTPs_CFG_FORM_MULTIPART_EN == DEF_ENABLED)))
1451
const HTTPs_CFG *p_cfg;
1452
#endif
1453
1454
#if (HTTPs_CFG_HDR_RX_EN == DEF_DISABLED)
1455
PP_UNUSED_PARAM(p_instance);
1456
#endif
1457
HTTPs_SET_PTR_STATS(p_ctr_stats, p_instance);
1458
1459
#if (((HTTPs_CFG_FORM_EN == DEF_ENABLED) \
1460
&& (HTTPs_CFG_FORM_MULTIPART_EN == DEF_ENABLED)) \
1461
|| (HTTPs_CFG_HDR_RX_EN == DEF_ENABLED))
1462
HTTPs_SET_PTR_ERRS(p_ctr_errs, p_instance);
1463
#endif
1464
#if ((HTTPs_CFG_HDR_RX_EN == DEF_ENABLED) \
1465
|| (HTTPs_CFG_ABSOLUTE_URI_EN == DEF_ENABLED) \
1466
|| ((HTTPs_CFG_FORM_EN == DEF_ENABLED) \
1467
&& (HTTPs_CFG_FORM_MULTIPART_EN == DEF_ENABLED)))
1468
p_cfg = p_instance->CfgPtr;
1469
#endif
1470
1471
// ------------------- #### NET-35. -------------------
1472
1473
p_field = p_conn->RxBufPtr; // Ptr should be prev moved to beginning of req hdr.
1474
while (p_field != DEF_NULL) { // Analyze each field in the req hdr section.
1475
p_field_end = Str_Str_N(p_field, // Find end of the field.
1476
STR_CR_LF,
1477
p_conn->RxBufLenRem);
1478
1479
// ------------------ ANALYZE FIELD -------------------
1480
if ((p_field_end != DEF_NULL) // If the field and val are present.
1481
&& (p_field_end > p_field) ) {
1482
len = p_field_end - p_field;
1483
// Get field key by comparing field name.
1484
field_key = HTTP_Dict_KeyGet(HTTP_Dict_HdrField,
1485
HTTP_Dict_HdrFieldSize,
1486
p_field,
1487
DEF_NO,
1488
len);
1489
if (field_key != HTTP_DICT_KEY_INVALID) {
1490
field = (HTTP_HDR_FIELD)field_key;
1491
#if (HTTPs_CFG_HDR_RX_EN == DEF_ENABLED)
1492
// Get field dictionary entry.
1493
p_field_dict_entry = HTTP_Dict_EntryGet(HTTP_Dict_HdrField,
1494
HTTP_Dict_HdrFieldSize,
1495
field);
1496
#endif
1497
1498
// ----------------- STO FIELD VALUE ------------------
1499
switch (field) {
1500
// ------------------- CONTENT TYPE -------------------
1501
case HTTP_HDR_FIELD_CONTENT_TYPE:
1502
// Get field val beginning.
1503
p_val = HTTPsReq_HdrParseValGet(p_field,
1504
HTTP_STR_HDR_FIELD_CONTENT_TYPE_LEN,
1505
p_field_end,
1506
&len);
1507
if (p_val != DEF_NULL) {
1508
len = p_field_end - p_val;
1509
// Get content type key by comparing field val name.
1510
field_key = HTTP_Dict_KeyGet(HTTP_Dict_ContentType,
1511
HTTP_Dict_ContentTypeSize,
1512
p_val,
1513
DEF_YES,
1514
len);
1515
if (field_key != HTTP_DICT_KEY_INVALID) {
1516
field = (HTTP_HDR_FIELD)field_key;
1517
p_conn->ReqContentType = (HTTP_CONTENT_TYPE)field;
1518
switch (field) {
1519
// ----------------- CONTENT TYPE APP -----------------
1520
case HTTP_CONTENT_TYPE_APP_FORM:
1521
HTTPs_STATS_INC(p_ctr_stats->Req_StatContentTypeFormAppRxdCtr);
1522
// Add content-type to Conn struct.
1523
break;
1524
1525
// -------------- CONTENT TYPE MULTIPART --------------
1526
case HTTP_CONTENT_TYPE_MULTIPART_FORM:
1527
HTTPs_STATS_INC(p_ctr_stats->Req_StatContentTypeFormMultipartRxdCtr);
1528
// Add content-type value to Conn struct.
1529
1530
#if ((HTTPs_CFG_FORM_EN == DEF_ENABLED) \
1531
&& (HTTPs_CFG_FORM_MULTIPART_EN == DEF_ENABLED))
1532
if (p_cfg->FormCfgPtr != DEF_NULL) {
1533
if (p_cfg->FormCfgPtr->MultipartEn == DEF_ENABLED) {
1534
// ----------------- STO BOUNDARY VAL -----------------
1535
// Boundary should be located after content type ...
1536
// val (see Note #3b).
1537
// Find end of content type val.
1538
p_dictionary = HTTP_Dict_EntryGet(HTTP_Dict_ContentType,
1539
HTTP_Dict_ContentTypeSize,
1540
HTTP_CONTENT_TYPE_MULTIPART_FORM);
1541
p_val = p_val + p_dictionary->StrLen + 1;
1542
p_val = HTTP_StrGraphSrchFirst(p_val, len);
1543
len = len - (p_val - p_field);
1544
1545
// Find beginning of boundary token.
1546
p_val = Str_Str_N(p_val,
1547
HTTP_STR_MULTIPART_BOUNDARY,
1548
sizeof(HTTP_STR_MULTIPART_BOUNDARY));
1549
1550
if (p_val == DEF_NULL) {
1551
*p_err = HTTPs_ERR_REQ_FORMAT_INVALID;
1552
return;
1553
}
1554
1555
// Boundary located after '='.
1556
p_val = Str_Char_N(p_val, len, ASCII_CHAR_EQUALS_SIGN);
1557
if (p_val == DEF_NULL) {
1558
*p_err = HTTPs_ERR_REQ_FORMAT_INVALID;
1559
return;
1560
}
1561
p_val++; // Remove space before boundary val.
1562
p_val = HTTP_StrGraphSrchFirst(p_val,
1563
len);
1564
len = p_field_end - p_val;
1565
1566
if (len > HTTPs_FORM_BOUNDARY_STR_LEN_MAX) {
1567
*p_err = HTTPs_ERR_REQ_FORMAT_INVALID;
1568
return;
1569
}
1570
1571
// Copy boundary val to Conn struct.
1572
Str_Copy_N(p_conn->FormBoundaryPtr,
1573
p_val,
1574
len);
1575
// Make sure to create a string.
1576
p_conn->FormBoundaryPtr[len] = ASCII_CHAR_NULL;
1577
1578
p_conn->FormBoundaryLen = len;
1579
}
1580
} else {
1581
HTTPs_ERR_INC(p_ctr_errs->Req_ErrBodyFormNotEn);
1582
}
1583
#endif
1584
break;
1585
1586
case HTTP_CONTENT_TYPE_UNKNOWN:
1587
HTTPs_STATS_INC(p_ctr_stats->Req_StatContentTypeUnknownRxdCtr);
1588
break;
1589
1590
default:
1591
HTTPs_STATS_INC(p_ctr_stats->Req_StatContentTypeOtherRxdCtr);
1592
break;
1593
}
1594
}
1595
} else { // Should not occurs.
1596
*p_err = HTTPs_ERR_REQ_MORE_DATA_REQUIRED;
1597
return;
1598
}
1599
break;
1600
1601
// ------------------- CONTENT LEN --------------------
1602
case HTTP_HDR_FIELD_CONTENT_LEN:
1603
// Find content len strg val.
1604
p_val = HTTPsReq_HdrParseValGet(p_field,
1605
HTTP_STR_HDR_FIELD_CONTENT_LEN_LEN,
1606
p_field_end,
1607
&len);
1608
1609
// Convert and copy val to Conn struct.
1610
p_conn->ReqContentLen = Str_ParseNbr_Int32U(p_val, 0, DEF_NBR_BASE_DEC);
1611
break;
1612
1613
// ----------------------- HOST -----------------------
1614
case HTTP_HDR_FIELD_HOST:
1615
#if (HTTPs_CFG_ABSOLUTE_URI_EN == DEF_ENABLED)
1616
// Find beginning of host string val.
1617
p_val = HTTPsReq_HdrParseValGet(p_field,
1618
HTTP_STR_HDR_FIELD_HOST_LEN,
1619
p_field_end,
1620
&len);
1621
1622
len = DEF_MIN(len, p_cfg->HostNameLenMax);
1623
1624
// Copy host name val in Conn struct.
1625
(void)Str_Copy_N(p_conn->HostPtr, p_val, len);
1626
// Make sure to create a string.
1627
p_conn->HostPtr[len] = ASCII_CHAR_NULL;
1628
#endif
1629
break;
1630
1631
// -------------------- CONNECTION --------------------
1632
case HTTP_HDR_FIELD_CONN:
1633
// Find beginning of connection hdr string val.
1634
p_val = HTTPsReq_HdrParseValGet(p_field,
1635
HTTP_STR_HDR_FIELD_CONN_LEN,
1636
p_field_end,
1637
&len);
1638
if (p_val != DEF_NULL) {
1639
len = p_field_end - p_val;
1640
// Get connection key by comparing field val name.
1641
field_key = HTTP_Dict_KeyGet(HTTP_Dict_HdrFieldConnVal,
1642
HTTP_Dict_HdrFieldConnValSize,
1643
p_val,
1644
DEF_NO,
1645
len);
1646
if (field_key != HTTP_DICT_KEY_INVALID) {
1647
switch (field_key) {
1648
case HTTP_HDR_FIELD_CONN_CLOSE:
1649
DEF_BIT_CLR(p_conn->Flags, (HTTPs_FLAGS)HTTPs_FLAG_CONN_PERSISTENT);
1650
break;
1651
1652
case HTTP_HDR_FIELD_CONN_PERSISTENT:
1653
default:
1654
break;
1655
}
1656
}
1657
}
1658
break;
1659
1660
default:
1661
#if (HTTPs_CFG_HDR_RX_EN == DEF_ENABLED)
1662
if ((p_cfg->HdrRxCfgPtr != DEF_NULL)
1663
&& (p_cfg->HooksPtr != DEF_NULL)) {
1664
keep = p_cfg->HooksPtr->OnReqHdrRxHook(p_instance,
1665
p_conn,
1666
p_cfg->Hooks_CfgPtr,
1667
field);
1668
1669
if ((keep == DEF_YES)
1670
&& (p_cfg->HdrRxCfgPtr->NbrPerConnMax != LIB_MEM_BLK_QTY_UNLIMITED)) {
1671
if (p_conn->HdrCtr >= p_cfg->HdrRxCfgPtr->NbrPerConnMax) {
1672
*p_err = HTTPs_ERR_REQ_HDR_OVERFLOW;
1673
return;
1674
}
1675
}
1676
1677
if (keep == DEF_YES) {
1678
RTOS_ERR local_err;
1679
switch (field) {
1680
default:
1681
val_type = HTTPs_HDR_VAL_TYPE_STR_DYN; // Only string data type supported.
1682
break;
1683
}
1684
// -------------- GET REQ HDR FIELD BLK ---------------
1685
p_req_hdr_blk = HTTPsMem_ReqHdrGet(p_instance,
1686
p_conn,
1687
(HTTP_HDR_FIELD)field,
1688
val_type,
1689
&local_err);
1690
if (p_req_hdr_blk == DEF_NULL) {
1691
*p_err = HTTPs_ERR_REQ_HDR_POOL_GET;
1692
return;
1693
}
1694
1695
p_val = HTTPsReq_HdrParseValGet(p_field,
1696
p_field_dict_entry->StrLen,
1697
p_field_end,
1698
&len);
1699
if (p_val != DEF_NULL) {
1700
len = p_field_end - p_val;
1701
1702
if (len > p_cfg->HdrRxCfgPtr->DataLenMax) {
1703
HTTPs_ERR_INC(p_ctr_errs->Req_ErrHdrDataLenInv);
1704
*p_err = HTTPS_ERR_REQ_HDR_INVALID_VAL_LEN;
1705
return;
1706
}
1707
1708
// ------------ UPDATE REQ HDR FIELD PARAM ------------
1709
Mem_Copy((void *) p_req_hdr_blk->ValPtr,
1710
(const void *) p_val,
1711
(CPU_SIZE_T) len);
1712
// Store only string.
1713
p_str = (CPU_CHAR *)p_req_hdr_blk->ValPtr + len;
1714
*p_str = ASCII_CHAR_NULL;
1715
p_req_hdr_blk->ValLen = len + 1;
1716
} else {
1717
*p_err = HTTPs_ERR_REQ_MORE_DATA_REQUIRED;
1718
return;
1719
}
1720
}
1721
}
1722
#endif
1723
break;
1724
}
1725
}
1726
1727
// --------------- UPDATE RX CONN PARAM ---------------
1728
p_field_end += STR_CR_LF_LEN;
1729
p_conn->RxBufLenRem -= p_field_end - p_field;
1730
p_field = p_field_end;
1731
p_conn->RxBufPtr = p_field;
1732
} else if (p_field_end == p_field) { // All field processed.
1733
p_conn->RxBufPtr += STR_CR_LF_LEN;
1734
p_conn->RxBufLenRem -= STR_CR_LF_LEN;
1735
*p_err = HTTPs_ERR_NONE;
1736
return;
1737
} else { // More data req'd to complete processing.
1738
if (p_conn->RxBufPtr != p_conn->BufPtr) { // Check if the buffer is not full.
1739
*p_err = HTTPs_ERR_REQ_MORE_DATA_REQUIRED;
1740
} else {
1741
*p_err = HTTPs_ERR_REQ_FORMAT_INVALID;
1742
}
1743
return;
1744
}
1745
}
1746
}
1747
1748
/****************************************************************************************************//**
1749
* HTTPsReq_HdrParseFieldValGet()
1750
*
1751
* @brief Get the beginning of a field value.
1752
*
1753
* @param p_field Pointer to the beginning of the field line.
1754
*
1755
* @param field_len Field length.
1756
*
1757
* @param p_field_end Pointer to the end of the field line.
1758
*
1759
* @param p_len_rem Pointer to a variable that will receive the remaining length.
1760
*
1761
* @return Pointer to the beginning of the field value.
1762
*
1763
* @note (1) RFC #2616, section "4.2 Message Headers" describe how Header field should be formated.
1764
*
1765
* - (a) HTTP header fields, which include general-header (section 4.5), request-header
1766
* (section 5.3), response-header (section 6.2), and entity-header (section 7.1)
1767
* fields, follow the same generic format as that given in Section 3.1 of RFC 822 [9].
1768
* Each header field consists of a name followed by a colon (":") and the field value.
1769
* Field names are case-insensitive. The field value MAY be preceded by any amount of
1770
* LWS, though a single SP is preferred. Header fields can be extended over multiple
1771
* lines by preceding each extra line with at least one SP or HT. Applications ought
1772
* to follow "common form", where one is known or indicated, when generating HTTP
1773
* constructs, since there might exist some implementations that fail to accept
1774
* anything
1775
*
1776
* beyond the common forms.
1777
*
1778
* message-header = field-name ":" [ field-value ]
1779
* field-name = token
1780
* field-value = *( field-content | LWS )
1781
* field-content = <the OCTETs making up the field-value
1782
* and consisting of either *TEXT or combinations
1783
* of token, separators, and quoted-string>
1784
*******************************************************************************************************/
1785
static CPU_CHAR *HTTPsReq_HdrParseValGet(CPU_CHAR *p_field,
1786
CPU_INT16U field_len,
1787
CPU_CHAR *p_field_end,
1788
CPU_INT16U *p_len_rem)
1789
{
1790
CPU_INT16U len;
1791
CPU_CHAR *p_val;
1792
1793
p_val = p_field + field_len;
1794
len = (p_field_end - p_val);
1795
1796
p_val = Str_Char_N(p_val, len, ASCII_CHAR_COLON); // Field val located after ':' (see Note #1a).
1797
p_val++;
1798
1799
len = (p_field_end - p_val);
1800
p_val = HTTP_StrGraphSrchFirst(p_val, len); // Remove blank space before field value.
1801
1802
*p_len_rem = (p_field_end - p_val);
1803
1804
return (p_val);
1805
}
1806
1807
/****************************************************************************************************//**
1808
* HTTPsReq_BodyForm()
1809
*
1810
* @brief (1) Receive and process post data inside received form:
1811
* - (a) Initialize connection parameters to parse post data.
1812
* - (b) Parse received data.
1813
* - (1) Parse application post data.
1814
* - (2) Parse multipart post data.
1815
*
1816
* @param p_instance Pointer to the instance.
1817
*
1818
* @param p_conn Pointer to the connection.
1819
*
1820
* @param p_err Pointer to variable that will receive the return error code from this function.
1821
*
1822
* @return DEF_YES, if Form processing is done.
1823
* DEF_NO, otherwise.
1824
*
1825
* @note (1) The ReqContentType should be validated before this function. Otherwise, an INTERNAL_ERROR
1826
* will be triggered.
1827
* Valid Content-Type(s) are:
1828
* - HTTPs_CONTENT_TYPE_REQ_APP ||
1829
* - HTTPs_CONTENT_TYPE_REQ_MULTIPART
1830
*
1831
* @note (2) Receive all post data is required before returning response since network buffers are not
1832
* freed before reading it and the stack could come locked if it run out of free buffer.
1833
*******************************************************************************************************/
1834
#if (HTTPs_CFG_FORM_EN == DEF_ENABLED)
1835
static CPU_BOOLEAN HTTPsReq_BodyForm(HTTPs_INSTANCE *p_instance,
1836
HTTPs_CONN *p_conn,
1837
HTTPs_ERR *p_err)
1838
{
1839
HTTPs_INSTANCE_ERRS *p_ctr_err = DEF_NULL;
1840
CPU_BOOLEAN done;
1841
1842
HTTPs_SET_PTR_ERRS(p_ctr_err, p_instance);
1843
1844
done = DEF_YES;
1845
1846
switch (p_conn->State) {
1847
// ----------------- PARSE DATA RX'D ------------------
1848
case HTTPs_CONN_STATE_REQ_BODY_FORM_APP_PARSE:
1849
// --------------- PARSE APP POST DATA ----------------
1850
done = HTTPsReq_BodyFormAppParse(p_instance, p_conn, p_err);
1851
break;
1852
1853
case HTTPs_CONN_STATE_REQ_BODY_FORM_MULTIPART_INIT:
1854
case HTTPs_CONN_STATE_REQ_BODY_FORM_MULTIPART_PARSE:
1855
case HTTPs_CONN_STATE_REQ_BODY_FORM_MULTIPART_FILE_OPEN:
1856
case HTTPs_CONN_STATE_REQ_BODY_FORM_MULTIPART_FILE_WR:
1857
// ------------ PARSE MULTIPART POST DATA -------------
1858
#if (HTTPs_CFG_FORM_MULTIPART_EN == DEF_ENABLED)
1859
done = HTTPsReq_BodyFormMultipartParse(p_instance, p_conn, p_err);
1860
#else
1861
HTTPs_ERR_INC(p_ctr_err->Req_ErrBodyFormMultipartNotEn);
1862
*p_err = HTTPs_ERR_CFG_INVALID_FORM_MULTIPART_EN;
1863
#endif
1864
break;
1865
1866
default:
1867
HTTPs_ERR_INC(p_ctr_err->Req_ErrBodyStateUnknownCtr);
1868
*p_err = HTTPs_ERR_STATE_UNKNOWN;
1869
RTOS_CRITICAL_FAIL_EXEC(RTOS_ERR_INVALID_STATE, DEF_NO);
1870
break;
1871
}
1872
1873
return (done);
1874
}
1875
#endif
1876
1877
/****************************************************************************************************//**
1878
* HTTPsReq_BodyFormAppParse()
1879
*
1880
* @brief (1) Parse form content types application:
1881
* - (a) Remove undesirable charters
1882
* - (b) Validate that the key pair value is completely present.
1883
* - (c) Parse control key pair value.
1884
* - (d) Update connection control parameters and state.
1885
*
1886
* @param p_instance Pointer to the instance.
1887
*
1888
* @param p_conn Pointer to the connection.
1889
*
1890
* @param p_err Pointer to variable that will receive the return error code from this function.
1891
*
1892
* @return DEF_YES, if Form parsing is finished.
1893
* DEF_NO, otherwise.
1894
*
1895
* @note (2) HTML 4.01 Specification section "17.13.4 Form content types" describes the application Form
1896
* content types:
1897
*
1898
* application/x-www-form-urlencoded
1899
*
1900
* This is the default content type. Forms submitted with this content type must be encoded
1901
* as follows:
1902
*
1903
* - (a) Control names and values are escaped. Space characters are replaced by `+', and then
1904
* reserved characters are escaped as described in [RFC1738], section 2.2: Non-alphanumeric
1905
* characters are replaced by '%HH', a percent sign and two hexadecimal digits representing
1906
* the ASCII code of the character. Line breaks are represented as "CR LF" pairs
1907
* (i.e., '%0D%0A').
1908
*
1909
* - (b) The control names/values are listed in the order they appear in the document. The name
1910
* is separated from the value by '=' and name/value pairs are separated from each other
1911
* by '&'.
1912
*******************************************************************************************************/
1913
#if (HTTPs_CFG_FORM_EN == DEF_ENABLED)
1914
static CPU_BOOLEAN HTTPsReq_BodyFormAppParse(HTTPs_INSTANCE *p_instance,
1915
HTTPs_CONN *p_conn,
1916
HTTPs_ERR *p_err)
1917
{
1918
CPU_CHAR *p_key_name;
1919
CPU_CHAR *p_key_next;
1920
CPU_INT32U len_content_rxd;
1921
CPU_INT16U len_str;
1922
CPU_BOOLEAN done;
1923
CPU_BOOLEAN result;
1924
1925
done = DEF_NO;
1926
// ------------- REMOVE UNDESIRABLE CHAR --------------
1927
// Remove possible blank char before first ctrl name.
1928
p_key_name = HTTP_StrGraphSrchFirst(p_conn->RxBufPtr,
1929
p_conn->RxBufLenRem);
1930
if (p_key_name == DEF_NULL) {
1931
*p_err = HTTPs_ERR_REQ_MORE_DATA_REQUIRED;
1932
goto exit;
1933
}
1934
1935
p_conn->RxBufLenRem -= (p_key_name - p_conn->RxBufPtr); // Update rem len avail in the rx buf.
1936
p_conn->ReqContentLenRxd += (p_key_name - p_conn->RxBufPtr); // Update content len received.
1937
p_conn->RxBufPtr = p_key_name; // Move rx buf ptr.
1938
1939
while (done != DEF_YES) {
1940
// ----------- VALIDATE CUR KEY/VAL PAIRS -------------
1941
p_key_next = Str_Char_N(p_key_name, // Srch beginning of next key/val pairs.
1942
p_conn->RxBufLenRem,
1943
ASCII_CHAR_AMPERSAND);
1944
1945
if (p_key_next == DEF_NULL) { // If next key/val pairs not found ...
1946
// ... determine if all data are received or next ...
1947
// ... key/val pairs are missing.
1948
len_content_rxd = p_conn->ReqContentLenRxd
1949
+ p_conn->RxBufLenRem;
1950
1951
if (len_content_rxd < p_conn->ReqContentLen) { // If data are missing ...
1952
*p_err = HTTPs_ERR_REQ_MORE_DATA_REQUIRED; // ... receive more data.
1953
goto exit;
1954
} else { // If all data received ...
1955
len_str = p_conn->RxBufLenRem; // ... last key/val pairs to parse.
1956
}
1957
} else { // Next key/val pairs found ...
1958
len_str = (p_key_next - p_key_name); // ... parse key/val pairs.
1959
}
1960
1961
// Add key-Value block to list.
1962
result = HTTPsReq_BodyFormAppKeyValBlkAdd(p_instance,
1963
p_conn,
1964
p_key_name,
1965
len_str,
1966
p_err);
1967
if (result == DEF_FAIL) {
1968
goto exit;
1969
}
1970
1971
// ------------ UPDATE CONN CTRLS & STATE -------------
1972
if (p_key_next != DEF_NULL) { // If not the last key/val pairs.
1973
len_str = p_key_next // Calculate data parsed ...
1974
- p_key_name // ... include key/val pairs separator.
1975
+ 1;
1976
1977
p_conn->ReqContentLenRxd += len_str; // Inc content len processed.
1978
p_conn->RxBufLenRem -= len_str; // Dec rem len available in rx buffer.
1979
p_key_name = p_key_next + 1; // Set cur key name to next key found.
1980
p_conn->RxBufPtr = p_key_name; // Update Rx buf ptr (i.e. if next key/val not found.)
1981
} else { // If last key/val pairs.
1982
p_conn->ReqContentLenRxd += p_conn->RxBufLenRem; // Inc content len processed.
1983
p_conn->RxBufLenRem = 0u; // No rem data avail in rx buffer.
1984
1985
if (p_conn->ReqContentLenRxd >= p_conn->ReqContentLen) {
1986
// If all data received and processed ...
1987
done = DEF_YES;
1988
} else { // If data are missing ...
1989
*p_err = HTTPs_ERR_REQ_MORE_DATA_REQUIRED; // ... receive more data.
1990
goto exit;
1991
}
1992
}
1993
}
1994
1995
*p_err = HTTPs_ERR_NONE;
1996
1997
exit:
1998
return (done);
1999
}
2000
#endif
2001
2002
/****************************************************************************************************//**
2003
* HTTPsReq_BodyFormAppKeyValBlkAdd()
2004
*
2005
* @brief Add received Application form entry to the Key-Value Form list.
2006
*
2007
* @param p_instance Pointer to the instance.
2008
*
2009
* @param p_conn Pointer to the connection.
2010
*
2011
* @param p_str Pointer to start of string containing the key-value data.
2012
*
2013
* @param str_len Length of the string.
2014
*
2015
* @param p_err Pointer to variable that will receive the return error code from this function.
2016
*
2017
* @return DEF_OK, if key-value block successfully added to list.
2018
* DEF_FAIL, otherwise.
2019
*******************************************************************************************************/
2020
#if (HTTPs_CFG_FORM_EN == DEF_ENABLED)
2021
static CPU_BOOLEAN HTTPsReq_BodyFormAppKeyValBlkAdd(HTTPs_INSTANCE *p_instance,
2022
HTTPs_CONN *p_conn,
2023
CPU_CHAR *p_str,
2024
CPU_SIZE_T str_len,
2025
HTTPs_ERR *p_err)
2026
{
2027
const HTTPs_CFG *p_cfg;
2028
HTTPs_KEY_VAL *p_key_val;
2029
CPU_BOOLEAN result;
2030
RTOS_ERR local_err;
2031
2032
RTOS_ERR_SET(local_err, RTOS_ERR_NONE);
2033
2034
p_cfg = p_instance->CfgPtr;
2035
2036
if (p_cfg->FormCfgPtr != DEF_NULL) {
2037
// Get the next key-value block available.
2038
if (p_cfg->FormCfgPtr->NbrPerConnMax != LIB_MEM_BLK_QTY_UNLIMITED) {
2039
if (p_conn->FormBlkAcquiredCtr >= p_cfg->FormCfgPtr->NbrPerConnMax) {
2040
*p_err = HTTPs_ERR_KEY_VAL_CFG_POOL_SIZE_INV;
2041
return (DEF_FAIL);
2042
}
2043
}
2044
2045
p_key_val = HTTPsMem_FormKeyValBlkGet(p_instance, p_conn, &local_err);
2046
if (p_key_val == DEF_NULL) { // If no key-value block available.
2047
*p_err = HTTPs_ERR_FORM_POOL_GET;
2048
return (DEF_FAIL);
2049
}
2050
2051
result = HTTPsReq_URL_EncodeStrParse(p_instance,
2052
p_conn,
2053
p_key_val,
2054
DEF_NO,
2055
p_str,
2056
str_len);
2057
if (result == DEF_FAIL) {
2058
*p_err = HTTPs_ERR_FORM_APP_PARSE_FAULT;
2059
return (DEF_FAIL);
2060
}
2061
2062
if (p_conn->FormDataListPtr == DEF_NULL) {
2063
p_key_val->NextPtr = DEF_NULL;
2064
} else {
2065
p_key_val->NextPtr = p_conn->FormDataListPtr;
2066
}
2067
p_conn->FormDataListPtr = p_key_val;
2068
}
2069
2070
*p_err = HTTPs_ERR_NONE;
2071
2072
return (DEF_OK);
2073
}
2074
#endif
2075
2076
/****************************************************************************************************//**
2077
* HTTPsReq_BodyFormMultipartParse()
2078
*
2079
* @brief Parse form content types multipart.
2080
*
2081
* @param p_instance Pointer to the instance.
2082
*
2083
* @param p_conn Pointer to the connection.
2084
*
2085
* @param p_err Pointer to variable that will receive the return error code from this function.
2086
*
2087
* @return DEF_YES, if Form parsing is finished.
2088
* DEF_NO, otherwise.
2089
*******************************************************************************************************/
2090
#if ((HTTPs_CFG_FORM_EN == DEF_ENABLED) \
2091
&& (HTTPs_CFG_FORM_MULTIPART_EN == DEF_ENABLED))
2092
static CPU_BOOLEAN HTTPsReq_BodyFormMultipartParse(HTTPs_INSTANCE *p_instance,
2093
HTTPs_CONN *p_conn,
2094
HTTPs_ERR *p_err)
2095
{
2096
CPU_BOOLEAN done;
2097
CPU_BOOLEAN file_done;
2098
CPU_BOOLEAN is_file;
2099
2100
done = DEF_NO;
2101
while (done != DEF_YES) {
2102
switch (p_conn->State) {
2103
case HTTPs_CONN_STATE_REQ_BODY_FORM_MULTIPART_INIT:
2104
case HTTPs_CONN_STATE_REQ_BODY_FORM_MULTIPART_PARSE:
2105
// Parse buffer for key-value pairs.
2106
is_file = HTTPsReq_BodyFormMultipartCtrlParse(p_instance,
2107
p_conn,
2108
p_err);
2109
switch (*p_err) {
2110
case HTTPs_ERR_NONE:
2111
if (is_file == DEF_YES) {
2112
p_conn->State = HTTPs_CONN_STATE_REQ_BODY_FORM_MULTIPART_FILE_OPEN;
2113
} else {
2114
if (p_conn->ReqContentLenRxd >= p_conn->ReqContentLen) {
2115
done = DEF_YES;
2116
}
2117
}
2118
break;
2119
2120
case HTTPs_ERR_REQ_MORE_DATA_REQUIRED:
2121
goto exit;
2122
2123
default:
2124
goto exit;
2125
}
2126
break;
2127
2128
case HTTPs_CONN_STATE_REQ_BODY_FORM_MULTIPART_FILE_OPEN:
2129
case HTTPs_CONN_STATE_REQ_BODY_FORM_MULTIPART_FILE_WR:
2130
file_done = HTTPsReq_BodyFormMultipartFileWr(p_instance,
2131
p_conn,
2132
p_err);
2133
switch (*p_err) {
2134
case HTTPs_ERR_NONE:
2135
if (file_done == DEF_YES) {
2136
p_conn->State = HTTPs_CONN_STATE_REQ_BODY_FORM_MULTIPART_INIT;
2137
} else {
2138
p_conn->State = HTTPs_CONN_STATE_REQ_BODY_FORM_MULTIPART_FILE_WR;
2139
}
2140
break;
2141
2142
case HTTPs_ERR_REQ_MORE_DATA_REQUIRED:
2143
p_conn->State = HTTPs_CONN_STATE_REQ_BODY_FORM_MULTIPART_FILE_WR;
2144
goto exit;
2145
2146
default:
2147
goto exit;
2148
}
2149
break;
2150
2151
default:
2152
*p_err = HTTPs_ERR_STATE_UNKNOWN;
2153
RTOS_CRITICAL_FAIL_EXEC(RTOS_ERR_INVALID_STATE, DEF_NO);
2154
}
2155
}
2156
2157
*p_err = HTTPs_ERR_NONE;
2158
2159
exit:
2160
return (done);
2161
}
2162
#endif
2163
2164
/****************************************************************************************************//**
2165
* HTTPsReq_BodyFormMultipartBoundarySrch()
2166
*
2167
* @brief Search for first boundary in data buffer.
2168
*
2169
* @param p_boundary Pointer to string that contains the boundary to search for.
2170
*
2171
* @param boundary_len Boundary length.
2172
*
2173
* @param p_buf Pointer to buffer where to start to search in.
2174
*
2175
* @param buf_len Buffer length.
2176
*
2177
* @param p_boundary_sep Pointer that will be set if the buffer end with possible beginning of a boundary.
2178
*
2179
* @return Pointer to the boundary, if successfully found.
2180
* Null pointer, otherwise.
2181
*******************************************************************************************************/
2182
#if ((HTTPs_CFG_FORM_EN == DEF_ENABLED) \
2183
&& (HTTPs_CFG_FORM_MULTIPART_EN == DEF_ENABLED))
2184
static CPU_CHAR *HTTPsReq_BodyFormMultipartBoundarySrch(CPU_CHAR *p_boundary,
2185
CPU_INT08U boundary_len,
2186
CPU_CHAR *p_buf,
2187
CPU_INT16U buf_len,
2188
CPU_CHAR **p_boundary_sep)
2189
{
2190
CPU_CHAR *p_boundary_found;
2191
CPU_CHAR *p_str;
2192
CPU_INT16U len;
2193
2194
PP_UNUSED_PARAM(p_boundary_sep);
2195
2196
if (buf_len <= 0) {
2197
*p_boundary_sep = DEF_NULL;
2198
p_boundary_found = DEF_NULL;
2199
goto exit;
2200
}
2201
2202
p_str = DEF_NULL;
2203
len = HTTPs_STR_MULTIPART_DATA_START_LEN;
2204
2205
p_str = HTTPs_StrMemSrch(p_buf, // Search for boundary separator in the buffer.
2206
buf_len,
2207
HTTPs_STR_MULTIPART_DATA_START,
2208
len);
2209
if (p_str == DEF_NULL) {
2210
if ((p_buf[buf_len - 1] == ASCII_CHAR_CARRIAGE_RETURN)
2211
|| (p_buf[buf_len - 1] == ASCII_CHAR_LINE_FEED)
2212
|| (p_buf[buf_len - 1] == ASCII_CHAR_HYPHEN_MINUS) ) {
2213
*p_boundary_sep = p_buf + buf_len - 1;
2214
p_boundary_found = DEF_NULL;
2215
goto exit;
2216
} else {
2217
*p_boundary_sep = DEF_NULL;
2218
p_boundary_found = DEF_NULL;
2219
goto exit;
2220
}
2221
}
2222
2223
*p_boundary_sep = p_str;
2224
2225
len = buf_len - (p_str - p_buf);
2226
if (len > boundary_len) {
2227
p_boundary_found = HTTPs_StrMemSrch(p_str, // Search for boundary in the buffer.
2228
len,
2229
p_boundary,
2230
boundary_len);
2231
2232
p_str = p_buf + buf_len - boundary_len - HTTPs_STR_MULTIPART_DATA_START_LEN;
2233
2234
// Boundary is not found :
2235
if ((p_boundary_found == DEF_NULL) // Case when separator "--" is found inside data, ...
2236
&& (*p_boundary_sep < p_str) ) { // ... set separator before end of buffer in case ...
2237
// ... start of boundary is at the end of buffer.
2238
*p_boundary_sep = p_str;
2239
}
2240
// Boundary is found :
2241
if (p_boundary_found != DEF_NULL) { // Insure that separator "--" is just before boundary...
2242
*p_boundary_sep = p_boundary_found - 2; // ... and not in data.
2243
}
2244
} else {
2245
p_boundary_found = DEF_NULL;
2246
goto exit;
2247
}
2248
2249
exit:
2250
return (p_boundary_found);
2251
}
2252
#endif
2253
2254
/****************************************************************************************************//**
2255
* HTTPsReq_BodyFormMultipartCtrlParse()
2256
*
2257
* @brief (1) Parse and store multipart key-value pair data:
2258
* - (a) Found Boundary in buffer.
2259
* - (b) Found if multipart field is a file.
2260
* - (c) Found the filename if it's a file or the key string if it's a key-value pair.
2261
* - (d) Acquire Form Key-Value block.
2262
* - (c) Store key string or filename string.
2263
* - (d) Store value string.
2264
*
2265
* @param p_instance Pointer to current HTTP server instance.
2266
*
2267
* @param p_conn Pointer to HTTP server current connection object.
2268
*
2269
* @param p_err Pointer to variable that will receive the return error code from this function.
2270
*
2271
* @return DEF_YES, if the current multipart field contains a file.
2272
* DEF_NO, otherwise.
2273
*******************************************************************************************************/
2274
#if ((HTTPs_CFG_FORM_EN == DEF_ENABLED) \
2275
&& (HTTPs_CFG_FORM_MULTIPART_EN == DEF_ENABLED))
2276
static CPU_BOOLEAN HTTPsReq_BodyFormMultipartCtrlParse(HTTPs_INSTANCE *p_instance,
2277
HTTPs_CONN *p_conn,
2278
HTTPs_ERR *p_err)
2279
{
2280
const HTTPs_CFG *p_cfg = p_instance->CfgPtr;
2281
CPU_CHAR *p_buf = p_conn->RxBufPtr;
2282
CPU_CHAR *p_boundary = DEF_NULL;
2283
CPU_CHAR *p_boundary_sep = DEF_NULL;
2284
CPU_CHAR *p_key = DEF_NULL;
2285
CPU_CHAR *p_filename = DEF_NULL;
2286
CPU_CHAR *p_filename_end = DEF_NULL;
2287
CPU_CHAR *p_end = DEF_NULL;
2288
CPU_CHAR *p_str = DEF_NULL;
2289
CPU_CHAR *p_data = DEF_NULL;
2290
HTTPs_KEY_VAL *p_key_val = DEF_NULL;
2291
CPU_CHAR path_sep;
2292
CPU_SIZE_T len = 0;
2293
CPU_BOOLEAN is_file = DEF_NO;
2294
RTOS_ERR local_err;
2295
2296
RTOS_ERR_SET(local_err, RTOS_ERR_NONE);
2297
2298
if (p_cfg->FormCfgPtr == DEF_NULL) {
2299
*p_err = HTTPs_ERR_CFG_NULL_PTR_FORM;
2300
return (DEF_YES);
2301
}
2302
2303
switch (p_conn->State) {
2304
// ---- FOUND BOUNDARY IN DATA RECEIVED IN BUFFER -----
2305
case HTTPs_CONN_STATE_REQ_BODY_FORM_MULTIPART_INIT:
2306
2307
// Search for boundary token in the buffer.
2308
p_boundary = HTTPsReq_BodyFormMultipartBoundarySrch(p_conn->FormBoundaryPtr,
2309
p_conn->FormBoundaryLen,
2310
p_conn->RxBufPtr,
2311
p_conn->RxBufLenRem,
2312
&p_boundary_sep);
2313
if (p_boundary == DEF_NULL) {
2314
if (p_conn->RxBufLenRem == p_conn->BufLen) {
2315
*p_err = HTTPs_ERR_CFG_INVALID_BUF_LEN;
2316
} else {
2317
*p_err = HTTPs_ERR_REQ_MORE_DATA_REQUIRED;
2318
}
2319
goto exit;
2320
}
2321
2322
if ((p_conn->FormDataListPtr != DEF_NULL) // Copy previous value to last key-val block.
2323
&& (p_boundary_sep != p_buf) ) {
2324
p_key_val = p_conn->FormDataListPtr;
2325
if (p_key_val->DataType != HTTPs_KEY_VAL_TYPE_FILE) {
2326
len = (p_boundary - p_buf) - HTTPs_STR_MULTIPART_DATA_START_LEN - STR_CR_LF_LEN;
2327
len = DEF_MIN(len, (CPU_SIZE_T)p_cfg->FormCfgPtr->ValLenMax - 1);
2328
Str_Copy_N(p_key_val->ValPtr, p_buf, len);
2329
p_key_val->ValPtr[len] = ASCII_CHAR_NULL;
2330
p_key_val->ValLen = len;
2331
}
2332
}
2333
2334
// Check if there is data after boundary in buffer.
2335
len = (p_conn->RxBufPtr + p_conn->RxBufLenRem) - p_boundary;
2336
if (len < (p_conn->FormBoundaryLen + HTTPs_STR_MULTIPART_LAST_LEN)) {
2337
p_conn->ReqContentLenRxd += (p_boundary_sep - p_buf);
2338
p_conn->RxBufLenRem -= (p_boundary_sep - p_buf);
2339
p_conn->RxBufPtr += (p_boundary_sep - p_buf);
2340
*p_err = HTTPs_ERR_REQ_MORE_DATA_REQUIRED;
2341
goto exit;
2342
}
2343
2344
p_str = p_boundary + p_conn->FormBoundaryLen;
2345
2346
p_str = Str_Str_N(p_str, // Find last boundary of multipart section.
2347
HTTPs_STR_MULTIPART_LAST,
2348
p_conn->RxBufLenRem);
2349
if ((p_str != DEF_NULL)
2350
&& (p_str == (p_boundary + p_conn->FormBoundaryLen))) {
2351
p_conn->ReqContentLenRxd += p_conn->RxBufLenRem;
2352
p_conn->RxBufPtr += p_conn->RxBufLenRem;
2353
p_conn->RxBufLenRem = 0;
2354
*p_err = HTTPs_ERR_NONE;
2355
goto exit;
2356
}
2357
2358
p_str = p_boundary + p_conn->FormBoundaryLen;
2359
2360
p_str = Str_Str_N(p_str, // Find end of boundary (CRLF).
2361
STR_CR_LF, // CRLF found must be just after the boundary.
2362
p_conn->RxBufLenRem);
2363
if ((p_str == DEF_NULL)
2364
|| (p_str != (p_boundary + p_conn->FormBoundaryLen))) {
2365
*p_err = HTTPs_ERR_FORM_FORMAT_INV;
2366
goto exit;
2367
}
2368
2369
p_str += STR_CR_LF_LEN;
2370
2371
// Update Connection parameters.
2372
p_conn->ReqContentLenRxd += (p_str - p_buf);
2373
p_conn->RxBufLenRem -= (p_str - p_buf);
2374
p_conn->RxBufPtr += (p_str - p_buf);
2375
2376
p_conn->State = HTTPs_CONN_STATE_REQ_BODY_FORM_MULTIPART_PARSE;
2377
break;
2378
2379
// -------- FOUND KEY STRING IN DATA RECEIVED ---------
2380
case HTTPs_CONN_STATE_REQ_BODY_FORM_MULTIPART_PARSE:
2381
p_data = Str_Str_N(p_buf, // Find end of key section.
2382
HTTPs_STR_MULTIPART_CTRL_END_SEC,
2383
p_conn->RxBufLenRem);
2384
if (p_data == DEF_NULL) {
2385
if (p_conn->RxBufLenRem == p_conn->BufLen) {
2386
*p_err = HTTPs_ERR_CFG_INVALID_BUF_LEN;
2387
} else {
2388
*p_err = HTTPs_ERR_REQ_MORE_DATA_REQUIRED;
2389
}
2390
goto exit;
2391
}
2392
2393
p_data += HTTPs_STR_MULTIPART_CTRL_END_SEC_LEN; // Beginning of data.
2394
2395
len = p_data - p_buf;
2396
2397
// Determine if it's a file.
2398
p_filename = HTTP_Dict_StrKeySrch(HTTP_Dict_MultipartField,
2399
HTTP_Dict_MultipartFieldSize,
2400
HTTP_MULTIPART_FIELD_FILE_NAME,
2401
p_conn->RxBufPtr,
2402
len);
2403
if (p_filename != DEF_NULL) {
2404
is_file = DEF_YES;
2405
2406
len = p_data - p_filename;
2407
// Find beginning of filename.
2408
p_filename = Str_Char_N(p_filename, len, ASCII_CHAR_QUOTATION_MARK);
2409
if (p_filename == DEF_NULL) {
2410
*p_err = HTTPs_ERR_FORM_FORMAT_INV;
2411
goto exit;
2412
}
2413
p_filename++;
2414
// Find end of filename.
2415
p_filename_end = Str_Char_N(p_filename, len, ASCII_CHAR_QUOTATION_MARK);
2416
if (p_filename_end == DEF_NULL) {
2417
*p_err = HTTPs_ERR_FORM_FORMAT_INV;
2418
goto exit;
2419
}
2420
*p_filename_end = ASCII_CHAR_NULL;
2421
}
2422
2423
// Find key name.
2424
p_key = HTTP_Dict_StrKeySrch(HTTP_Dict_MultipartField,
2425
HTTP_Dict_MultipartFieldSize,
2426
HTTP_MULTIPART_FIELD_NAME,
2427
p_conn->RxBufPtr,
2428
p_conn->RxBufLenRem);
2429
if (p_key != DEF_NULL) {
2430
len = p_data - p_key;
2431
// Find beginning of key.
2432
p_key = Str_Char_N(p_key, len, ASCII_CHAR_QUOTATION_MARK);
2433
if (p_key == DEF_NULL) {
2434
*p_err = HTTPs_ERR_FORM_FORMAT_INV;
2435
goto exit;
2436
}
2437
p_key++;
2438
// Find end of key name.
2439
p_end = Str_Char_N(p_key, len, ASCII_CHAR_QUOTATION_MARK);
2440
if (p_end == DEF_NULL) {
2441
*p_err = HTTPs_ERR_FORM_FORMAT_INV;
2442
goto exit;
2443
}
2444
}
2445
2446
if ((p_filename == DEF_NULL) // 'filename' or 'name' string MUST be found.
2447
&& (p_key == DEF_NULL)) {
2448
*p_err = HTTPs_ERR_FORM_FORMAT_INV;
2449
goto exit;
2450
}
2451
2452
// --------------- ACQUIRE KEY-VALUE BLK --------------
2453
if (p_cfg->FormCfgPtr->NbrPerConnMax != LIB_MEM_BLK_QTY_UNLIMITED) {
2454
if (p_conn->FormBlkAcquiredCtr >= p_cfg->FormCfgPtr->NbrPerConnMax) {
2455
*p_err = HTTPs_ERR_KEY_VAL_CFG_POOL_SIZE_INV;
2456
goto exit;
2457
}
2458
}
2459
2460
p_key_val = HTTPsMem_FormKeyValBlkGet(p_instance,
2461
p_conn,
2462
&local_err);
2463
if (p_key_val == DEF_NULL) { // If no Key-Value block available.
2464
*p_err = HTTPs_ERR_FORM_POOL_GET;
2465
goto exit; // Returns with p_err from previous fnct call.
2466
} else {
2467
if (p_conn->FormDataListPtr == DEF_NULL) {
2468
p_key_val->NextPtr = DEF_NULL;
2469
} else {
2470
p_key_val->NextPtr = p_conn->FormDataListPtr;
2471
}
2472
p_conn->FormDataListPtr = p_key_val;
2473
}
2474
2475
if (p_key != DEF_NULL) { // Copy Key string found to key-value block.
2476
len = p_end - p_key;
2477
len = DEF_MIN(len, (CPU_SIZE_T)p_cfg->FormCfgPtr->KeyLenMax - 1);
2478
Str_Copy_N(p_key_val->KeyPtr, p_key, len);
2479
p_key_val->KeyPtr[len] = ASCII_CHAR_NULL;
2480
p_key_val->KeyLen = len;
2481
2482
if (p_filename == DEF_NULL) {
2483
p_key_val->DataType = HTTPs_KEY_VAL_TYPE_PAIR;
2484
}
2485
2486
p_conn->State = HTTPs_CONN_STATE_REQ_BODY_FORM_MULTIPART_INIT;
2487
}
2488
2489
if (p_filename != DEF_NULL) {
2490
p_key_val->DataType = HTTPs_KEY_VAL_TYPE_FILE;
2491
2492
if (p_key == DEF_NULL) {
2493
p_key_val->KeyPtr[0] = ASCII_CHAR_NULL;
2494
}
2495
2496
switch (p_cfg->FS_Type) {
2497
case HTTPs_FS_TYPE_NONE:
2498
path_sep = HTTPs_PATH_SEP_CHAR_DFLT;
2499
break;
2500
2501
case HTTPs_FS_TYPE_STATIC:
2502
case HTTPs_FS_TYPE_DYN:
2503
#if (HTTPs_CFG_FS_PRESENT_EN == DEF_ENABLED)
2504
path_sep = p_instance->FS_PathSepChar;
2505
break;
2506
#else
2507
*p_err = HTTPs_ERR_CFG_INVALID_FS_EN;
2508
goto exit;
2509
#endif
2510
2511
default:
2512
*p_err = HTTPs_ERR_CFG_INVALID_FS_TYPE;
2513
goto exit;
2514
}
2515
2516
HTTPs_StrPathFormat(p_filename, // Format file path and store in value string.
2517
p_cfg->FormCfgPtr->MultipartFileUploadFolderPtr,
2518
p_key_val->ValPtr,
2519
p_cfg->FormCfgPtr->ValLenMax,
2520
path_sep);
2521
2522
len = Str_Len_N(p_key_val->ValPtr, p_cfg->FormCfgPtr->ValLenMax);
2523
2524
p_key_val->ValLen = len;
2525
2526
p_conn->State = HTTPs_CONN_STATE_REQ_BODY_FORM_MULTIPART_FILE_OPEN;
2527
}
2528
2529
p_conn->ReqContentLenRxd += (p_data - p_buf);
2530
p_conn->RxBufPtr += (p_data - p_buf);
2531
p_conn->RxBufLenRem -= (p_data - p_buf);
2532
break;
2533
2534
default:
2535
*p_err = HTTPs_ERR_STATE_UNKNOWN;
2536
RTOS_CRITICAL_FAIL_EXEC(RTOS_ERR_INVALID_STATE, DEF_NO);
2537
}
2538
2539
*p_err = HTTPs_ERR_NONE;
2540
2541
exit:
2542
return (is_file);
2543
}
2544
#endif
2545
2546
/****************************************************************************************************//**
2547
* HTTPsReq_BodyFormMultipartFileWr()
2548
*
2549
* @brief (1) File received in multipart form processing:
2550
* - (a) Open file
2551
* - (b) Write data to file until boundary is found in buffer.
2552
* - (c) Close file, if all file data is received or in case of an error.
2553
*
2554
* @param p_instance Pointer to current HTTP server instance.
2555
*
2556
* @param p_conn Pointer to HTTP server current connection object.
2557
*
2558
* @param p_err Pointer to variable that will receive the return error code from this function.
2559
*
2560
* @return DEF_YES, if file file writing is done and file is closed.
2561
* DEF_NO, otherwise.
2562
*******************************************************************************************************/
2563
#if ((HTTPs_CFG_FORM_EN == DEF_ENABLED) \
2564
&& (HTTPs_CFG_FORM_MULTIPART_EN == DEF_ENABLED))
2565
static CPU_BOOLEAN HTTPsReq_BodyFormMultipartFileWr(HTTPs_INSTANCE *p_instance,
2566
HTTPs_CONN *p_conn,
2567
HTTPs_ERR *p_err)
2568
{
2569
const HTTPs_CFG *p_cfg = p_instance->CfgPtr;
2570
const NET_FS_API *p_fs_api;
2571
CPU_CHAR *p_boundary;
2572
CPU_CHAR *p_boundary_sep;
2573
CPU_SIZE_T len;
2574
CPU_SIZE_T tmp;
2575
CPU_SIZE_T len_wr;
2576
CPU_SIZE_T len_wr_tot;
2577
CPU_BOOLEAN fs_op;
2578
CPU_BOOLEAN done = DEF_NO;
2579
HTTPs_INSTANCE_STATS *p_ctr_stats = DEF_NULL;
2580
2581
HTTPs_SET_PTR_STATS(p_ctr_stats, p_instance);
2582
2583
switch (p_cfg->FS_Type) {
2584
case HTTPs_FS_TYPE_NONE:
2585
p_fs_api = DEF_NULL;
2586
break;
2587
2588
case HTTPs_FS_TYPE_STATIC:
2589
#if (HTTPs_CFG_FS_PRESENT_EN == DEF_ENABLED)
2590
p_fs_api = ((HTTPs_CFG_FS_STATIC *)p_cfg->FS_CfgPtr)->FS_API_Ptr;
2591
#else
2592
p_fs_api = DEF_NULL;
2593
#endif
2594
break;
2595
2596
case HTTPs_FS_TYPE_DYN:
2597
#if (HTTPs_CFG_FS_PRESENT_EN == DEF_ENABLED)
2598
p_fs_api = ((HTTPs_CFG_FS_DYN *)p_cfg->FS_CfgPtr)->FS_API_Ptr;
2599
#else
2600
p_fs_api = DEF_NULL;
2601
#endif
2602
break;
2603
2604
default:
2605
*p_err = HTTPs_ERR_CFG_INVALID_FS_TYPE;
2606
goto exit;
2607
}
2608
2609
done = DEF_NO;
2610
2611
if (p_fs_api == DEF_NULL) {
2612
HTTPs_STATS_INC(p_ctr_stats->Req_StatFormFileUploadNoFS_Ctr);
2613
}
2614
2615
switch (p_conn->State) {
2616
case HTTPs_CONN_STATE_REQ_BODY_FORM_MULTIPART_FILE_OPEN:
2617
if ((p_fs_api != DEF_NULL)
2618
&& (p_cfg->FormCfgPtr->MultipartFileUploadEn == DEF_ENABLED)) {
2619
if (p_cfg->FormCfgPtr->MultipartFileUploadOverWrEn == DEF_ENABLED) {
2620
p_conn->DataPtr = p_fs_api->Open(p_conn->FormDataListPtr->ValPtr,
2621
NET_FS_FILE_MODE_CREATE,
2622
NET_FS_FILE_ACCESS_WR);
2623
if (p_conn->DataPtr == DEF_NULL) {
2624
*p_err = HTTPs_ERR_FORM_FILE_UPLOAD_OPEN;
2625
goto exit;
2626
}
2627
HTTPs_STATS_INC(p_ctr_stats->Req_StatFormFileUploadOpenedCtr);
2628
} else {
2629
p_conn->DataPtr = p_fs_api->Open(p_conn->FormDataListPtr->ValPtr,
2630
NET_FS_FILE_MODE_CREATE_NEW,
2631
NET_FS_FILE_ACCESS_WR);
2632
}
2633
}
2634
p_conn->State = HTTPs_CONN_STATE_REQ_BODY_FORM_MULTIPART_FILE_WR;
2635
break;
2636
2637
case HTTPs_CONN_STATE_REQ_BODY_FORM_MULTIPART_FILE_WR:
2638
p_boundary_sep = DEF_NULL;
2639
// Search for boundary token in the buffer.
2640
p_boundary = HTTPsReq_BodyFormMultipartBoundarySrch(p_conn->FormBoundaryPtr,
2641
p_conn->FormBoundaryLen,
2642
p_conn->RxBufPtr,
2643
p_conn->RxBufLenRem,
2644
&p_boundary_sep);
2645
2646
if (p_boundary_sep == DEF_NULL) { // Calculate length of data to write in file.
2647
len = p_conn->RxBufLenRem;
2648
} else {
2649
tmp = p_boundary_sep - p_conn->RxBufPtr;
2650
if (tmp < STR_CR_LF_LEN) {
2651
len = 0;
2652
} else {
2653
len = tmp - STR_CR_LF_LEN;
2654
}
2655
}
2656
// Write data to the file.
2657
if ((p_fs_api != DEF_NULL)
2658
&& (p_cfg->FormCfgPtr->MultipartFileUploadEn == DEF_ENABLED)
2659
&& (p_conn->DataPtr != DEF_NULL) ) {
2660
len_wr_tot = 0;
2661
fs_op = DEF_OK;
2662
while ((fs_op != DEF_FAIL)
2663
&& (len_wr_tot < len) ) {
2664
fs_op = p_fs_api->Wr(p_conn->DataPtr,
2665
(CPU_INT08U *)p_conn->RxBufPtr,
2666
len,
2667
&len_wr);
2668
2669
len_wr_tot += len_wr;
2670
}
2671
2672
if (fs_op == DEF_FAIL) { // If write operation fault exit with error.
2673
p_conn->ReqContentLenRxd += p_conn->RxBufLenRem;
2674
p_conn->RxBufPtr += p_conn->RxBufLenRem;
2675
p_conn->RxBufLenRem = 0;
2676
2677
HTTPs_STATS_INC(p_ctr_stats->Req_StatFormFileUploadClosedCtr);
2678
p_fs_api->Close(p_conn->DataPtr);
2679
p_conn->DataPtr = DEF_NULL;
2680
2681
done = DEF_YES;
2682
*p_err = HTTPs_ERR_FILE_WR_FAULT;
2683
goto exit;
2684
}
2685
} else {
2686
len_wr_tot = len;
2687
}
2688
2689
// Update Connection parameters.
2690
p_conn->RxBufPtr += len_wr_tot;
2691
p_conn->RxBufLenRem -= len_wr_tot;
2692
p_conn->ReqContentLenRxd += len_wr_tot;
2693
2694
if (p_boundary == DEF_NULL) {
2695
p_conn->State = HTTPs_CONN_STATE_REQ_BODY_FORM_MULTIPART_FILE_WR;
2696
*p_err = HTTPs_ERR_REQ_MORE_DATA_REQUIRED;
2697
goto exit;
2698
} else {
2699
p_conn->RxBufPtr += STR_CR_LF_LEN;
2700
p_conn->RxBufLenRem -= STR_CR_LF_LEN;
2701
p_conn->ReqContentLenRxd += STR_CR_LF_LEN;
2702
2703
if ((p_fs_api != DEF_NULL)
2704
&& (p_cfg->FormCfgPtr->MultipartFileUploadEn == DEF_ENABLED)
2705
&& (p_conn->DataPtr != DEF_NULL) ) {
2706
HTTPs_STATS_INC(p_ctr_stats->Req_StatFormFileUploadClosedCtr);
2707
p_fs_api->Close(p_conn->DataPtr);
2708
}
2709
p_conn->DataPtr = DEF_NULL;
2710
2711
done = DEF_YES;
2712
}
2713
break;
2714
2715
default:
2716
*p_err = HTTPs_ERR_STATE_UNKNOWN;
2717
RTOS_CRITICAL_FAIL_EXEC(RTOS_ERR_INVALID_STATE, DEF_NO);
2718
}
2719
2720
*p_err = HTTPs_ERR_NONE;
2721
2722
exit:
2723
return (done);
2724
}
2725
#endif
2726
2727
/****************************************************************************************************//**
2728
* HTTPsReq_URL_EncodeStrParse()
2729
*
2730
* @brief Populate a new Key-Value block from a URL Encoded String.
2731
*
2732
* @param p_instance Pointer to the instance.
2733
*
2734
* @param p_conn Pointer to the connection.
2735
*
2736
* @param p_key_val Pointer to the Key-Value block to populate.
2737
*
2738
* @param from_query DEF_YES, if parsing a Query String.
2739
* DEF_NO, if parsing a HTTP Form.
2740
*
2741
* @param p_str Pointer to start of the URL encoded string.
2742
*
2743
* @param str_len Length of the URL encoded string.
2744
*
2745
* @return DEF_OK, if parsing is successful.
2746
* DEF_FAIL, otherwise.
2747
*******************************************************************************************************/
2748
#if ((HTTPs_CFG_QUERY_STR_EN == DEF_ENABLED) \
2749
|| ((HTTPs_CFG_FORM_EN == DEF_ENABLED)))
2750
static CPU_BOOLEAN HTTPsReq_URL_EncodeStrParse(HTTPs_INSTANCE *p_instance,
2751
HTTPs_CONN *p_conn,
2752
HTTPs_KEY_VAL *p_key_val,
2753
CPU_BOOLEAN from_query,
2754
CPU_CHAR *p_str,
2755
CPU_SIZE_T str_len)
2756
{
2757
const HTTPs_CFG *p_cfg;
2758
CPU_CHAR *p_key;
2759
CPU_CHAR *p_val;
2760
CPU_CHAR *p_str_sep;
2761
CPU_SIZE_T key_len;
2762
CPU_SIZE_T val_len;
2763
CPU_SIZE_T key_len_cfg;
2764
CPU_SIZE_T val_len_cfg;
2765
CPU_BOOLEAN result;
2766
2767
p_cfg = p_instance->CfgPtr;
2768
2769
if (from_query == DEF_YES) {
2770
if (p_cfg->QueryStrCfgPtr != DEF_NULL) {
2771
key_len_cfg = p_cfg->QueryStrCfgPtr->KeyLenMax - 1;
2772
val_len_cfg = p_cfg->QueryStrCfgPtr->ValLenMax - 1;
2773
} else {
2774
p_conn->ErrCode = HTTPs_ERR_CFG_NULL_PTR_QUERY_STR;
2775
return (DEF_FAIL);
2776
}
2777
} else {
2778
if (p_cfg->FormCfgPtr != DEF_NULL) {
2779
key_len_cfg = p_cfg->FormCfgPtr->KeyLenMax - 1;
2780
val_len_cfg = p_cfg->FormCfgPtr->ValLenMax - 1;
2781
} else {
2782
p_conn->ErrCode = HTTPs_ERR_CFG_NULL_PTR_FORM;
2783
return (DEF_FAIL);
2784
}
2785
}
2786
2787
// Find separator "=".
2788
p_str_sep = Str_Char_N(p_str, str_len, ASCII_CHAR_EQUALS_SIGN);
2789
2790
p_str[str_len] = ASCII_CHAR_NULL;
2791
2792
if (p_str_sep != DEF_NULL) {
2793
p_val = p_str_sep + 1;
2794
p_key = p_str;
2795
} else {
2796
p_val = p_str_sep;
2797
p_key = DEF_NULL;
2798
}
2799
2800
// --------------- COPY CTRL NAME & VAL ---------------
2801
// Get and copy the ctrl name.
2802
if (p_key != DEF_NULL) {
2803
key_len = p_str_sep - p_key;
2804
key_len = DEF_MIN(key_len, key_len_cfg);
2805
2806
Str_Copy_N(p_key_val->KeyPtr,
2807
p_key,
2808
key_len);
2809
2810
p_key_val->DataType = HTTPs_KEY_VAL_TYPE_PAIR;
2811
} else {
2812
key_len = 0;
2813
p_key_val->DataType = HTTPs_KEY_VAL_TYPE_VAL;
2814
}
2815
2816
p_key_val->KeyPtr[key_len] = ASCII_CHAR_NULL;
2817
p_key_val->KeyLen = key_len;
2818
2819
// Get and copy the value.
2820
val_len = p_str + str_len - p_val;
2821
val_len = DEF_MIN(val_len, val_len_cfg);
2822
2823
Str_Copy_N(p_key_val->ValPtr,
2824
p_val,
2825
val_len);
2826
2827
p_key_val->ValPtr[val_len] = ASCII_CHAR_NULL;
2828
p_key_val->ValLen = val_len;
2829
2830
result = HTTP_URL_DecodeReplaceStr(p_key_val->KeyPtr,
2831
&p_key_val->KeyLen);
2832
if (result == DEF_FAIL) {
2833
return (DEF_FAIL);
2834
}
2835
2836
result = HTTP_URL_DecodeReplaceStr(p_key_val->ValPtr,
2837
&p_key_val->ValLen);
2838
if (result == DEF_FAIL) {
2839
return (DEF_FAIL);
2840
}
2841
2842
return (DEF_OK);
2843
}
2844
#endif
2845
2846
/********************************************************************************************************
2847
********************************************************************************************************
2848
* DEPENDENCIES & AVAIL CHECK(S) END
2849
********************************************************************************************************
2850
*******************************************************************************************************/
2851
2852
#endif // RTOS_MODULE_NET_HTTP_SERVER_AVAIL