1
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
32
41
42
43
44
45
46
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
74
75
81
82
85
86
87
88
89
95
96
97
98
99
105
106
107
108
111
112
113
114
115
116
117
118
119
120
121
122
123
129
130
131
132
133
140
141
142
143
144
145
146
147
148
149
151
152
156
157
160
164
165
170
171
172
173
174
175
176
177
178
179
180
181
183
184
185
186
187
188
189
190
191
192
193
196
197
198
199
200
201
202
203
204
211
212
213
215
216
217
218
219
220
225
226
228
229
230
231
232
233
234
235
236
237
238
244
245
246
247
248
249
250
251
252
255
256
257
258
259
260
261
262
263
264
265
266
267
274
275
276
277
278
279
280
281
282
288
289
290
291
292
293
294
295
296
299
300
301
302
303
304
305
306
316
317
318
319
321
322
328
329
330
331
332
333
334
335
336
337
338
339
346
352
353
354
355
356
357
358
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
385
386
387
393
394
395
396
397
401
402
403
404
405
406
407
408
409
410
413
414
415
416
417
418
424
425
429
434
435
436
437
438
439
440
441
442
445
446
447
448
449
450
465
466
470
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
492
493
496
497
519
520
521
522
523
524
525
526
527
528
529
530
531
553
554
555
563
564
565
566
567
568
569
583
584
585
586
587
588
589
590
591
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
648
649
651
652
653
654
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
703
704
705
711
712
713
714
715
716
717
718
719
720
721
722
723
724
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
765
766
767
768
769
776
777
778
779
782
783
786
787
788
789
790
791
792
795
796
797
798
800
801
802
803
804
805
806
807
809
810
811
812
816
817
818
819
820
826
827
828
829
830
831
832
833
836
850
851
852
853
854
857
858
859
860
861
862
864
865
868
869
870
873
874
884
885
886
887
889
892
893
894
895
896
897
898
899
900
903
904
905
906
907
908
909
910
911
914
915
918
919
923
924
925
926
927
928
931
932
933
934
935
936
939
940
943
944
948
949
950
951
952
953
954
955
956
958
959
960
961
964
965
966
967
968
969
970
971
972
975
976
979
980
981
982
983
984
985
988
989
992
993
997
998
999
1000
1001
1002
1003
1005
1008
1009
1010
1011
1012
1013
1014
1015
1016
1019
1020
1021
1022
1023
1024
1025
1026
1027
1030
1031
1034
1035
1036
1037
1038
1039
1040
1041
1044
1045
1048
1049
1053
1054
1055
1056
1057
1058
1059
1061
1064
1065
1066
1067
1068
1069
1070
1071
1072
1075
1076
1077
1078
1079
1080
1081
1082
1083
1086
1087
1088
1089
1090
1091
1092
1093
1094
1097
1098
1099
1100
1101
1102
1103
1105
1106
1109
1110
1111
1114
1115
1117
1118
1121
1122
1123
1124
1125
1126
1127
1129
1132
1133
1134
1135
1136
1137
1138
1139
1140
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1162
1163
1167
1168
1173
1174
1175
1176
1177
1178
/* ... */
#include <stdlib.h>
#include <string.h>
#include <sys/param.h>
#include <esp_log.h>
#include <esp_err.h>
#include <http_parser.h>
#include <inttypes.h>
#include <esp_http_server.h>
#include "esp_httpd_priv.h"
#include "osal.h"10 includes
static const char *TAG = "httpd_parse";
typedef struct {
http_parser_settings settings;
struct httpd_req *req;
/* ... */
enum {
PARSING_IDLE = 0,
PARSING_URL,
PARSING_HDR_FIELD,
PARSING_HDR_VALUE,
PARSING_BODY,
PARSING_COMPLETE,
PARSING_FAILED
}{ ... } status;
httpd_err_code_t error;
struct {
const char *at;
size_t length;
}{ ... } last;
bool paused;
size_t pre_parsed;
size_t raw_datalen;
}{ ... } parser_data_t;
static esp_err_t verify_url (http_parser *parser)
{
parser_data_t *parser_data = (parser_data_t *) parser->data;
struct httpd_req *r = parser_data->req;
struct httpd_req_aux *ra = r->aux;
struct http_parser_url *res = &ra->url_parse_res;
const char *at = parser_data->last.at;
size_t length = parser_data->last.length;
r->method = parser->method;
if (r->method < 0) {
ESP_LOGW(TAG, LOG_FMT("HTTP method not supported (%d)"), r->method);
parser_data->error = HTTPD_501_METHOD_NOT_IMPLEMENTED;
return ESP_FAIL;
}{...}
if (sizeof(r->uri) < (length + 1)) {
ESP_LOGW(TAG, LOG_FMT("URI length (%"NEWLIB_NANO_COMPAT_FORMAT") greater than supported (%"NEWLIB_NANO_COMPAT_FORMAT")"),
NEWLIB_NANO_COMPAT_CAST(length), NEWLIB_NANO_COMPAT_CAST(sizeof(r->uri)));
parser_data->error = HTTPD_414_URI_TOO_LONG;
return ESP_FAIL;
}{...}
/* ... */
strlcpy((char *)r->uri, at, (length + 1));
ESP_LOGD(TAG, LOG_FMT("received URI = %s"), r->uri);
if (!((parser->http_major == 1) && ((parser->http_minor == 0) || (parser->http_minor == 1)))) {
ESP_LOGW(TAG, LOG_FMT("unsupported HTTP version = %d.%d"),
parser->http_major, parser->http_minor);
parser_data->error = HTTPD_505_VERSION_NOT_SUPPORTED;
return ESP_FAIL;
}{...}
http_parser_url_init(res);
if (http_parser_parse_url(r->uri, strlen(r->uri),
r->method == HTTP_CONNECT, res)) {
ESP_LOGW(TAG, LOG_FMT("http_parser_parse_url failed with errno = %d"),
parser->http_errno);
parser_data->error = HTTPD_400_BAD_REQUEST;
return ESP_FAIL;
}{...}
return ESP_OK;
}{ ... }
/* ... */
static esp_err_t cb_url(http_parser *parser,
const char *at, size_t length)
{
parser_data_t *parser_data = (parser_data_t *) parser->data;
if (parser_data->status == PARSING_IDLE) {
ESP_LOGD(TAG, LOG_FMT("message begin"));
parser_data->last.at = at;
parser_data->last.length = 0;
parser_data->status = PARSING_URL;
}{...} else if (parser_data->status != PARSING_URL) {
ESP_LOGE(TAG, LOG_FMT("unexpected state transition"));
parser_data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
parser_data->status = PARSING_FAILED;
return ESP_FAIL;
}{...}
ESP_LOGD(TAG, LOG_FMT("processing url = %.*s"), (int)length, at);
if ((parser_data->last.length += length) > HTTPD_MAX_URI_LEN) {
ESP_LOGW(TAG, LOG_FMT("URI length (%"NEWLIB_NANO_COMPAT_FORMAT") greater than supported (%d)"),
NEWLIB_NANO_COMPAT_CAST(parser_data->last.length), HTTPD_MAX_URI_LEN);
parser_data->error = HTTPD_414_URI_TOO_LONG;
parser_data->status = PARSING_FAILED;
return ESP_FAIL;
}{...}
return ESP_OK;
}{ ... }
static esp_err_t pause_parsing(http_parser *parser, const char* at)
{
parser_data_t *parser_data = (parser_data_t *) parser->data;
struct httpd_req *r = parser_data->req;
struct httpd_req_aux *ra = r->aux;
/* ... */
ssize_t unparsed = parser_data->raw_datalen - (at - ra->scratch);
if (unparsed < 0) {
ESP_LOGE(TAG, LOG_FMT("parsing beyond valid data = %d"), (int)(-unparsed));
return ESP_ERR_INVALID_STATE;
}{...}
/* ... */
if (unparsed && (unparsed != httpd_unrecv(r, at, unparsed))) {
ESP_LOGE(TAG, LOG_FMT("data too large for un-recv = %d"), (int)unparsed);
return ESP_FAIL;
}{...}
/* ... */
parser_data->pre_parsed = unparsed;
http_parser_pause(parser, 1);
parser_data->paused = true;
ESP_LOGD(TAG, LOG_FMT("paused"));
return ESP_OK;
}{ ... }
static size_t continue_parsing(http_parser *parser, size_t length)
{
parser_data_t *data = (parser_data_t *) parser->data;
/* ... */
length = MIN(length, data->pre_parsed);
data->pre_parsed -= length;
ESP_LOGD(TAG, LOG_FMT("skip pre-parsed data of size = %"NEWLIB_NANO_COMPAT_FORMAT), NEWLIB_NANO_COMPAT_CAST(length));
http_parser_pause(parser, 0);
data->paused = false;
ESP_LOGD(TAG, LOG_FMT("un-paused"));
return length;
}{ ... }
/* ... */
static esp_err_t cb_header_field(http_parser *parser, const char *at, size_t length)
{
parser_data_t *parser_data = (parser_data_t *) parser->data;
struct httpd_req *r = parser_data->req;
struct httpd_req_aux *ra = r->aux;
if (parser_data->status == PARSING_URL) {
if (verify_url(parser) != ESP_OK) {
/* ... */
parser_data->status = PARSING_FAILED;
return ESP_FAIL;
}{...}
ESP_LOGD(TAG, LOG_FMT("headers begin"));
/* ... */
parser_data->last.at = ra->scratch;
parser_data->last.length = 0;
parser_data->status = PARSING_HDR_FIELD;
if (pause_parsing(parser, at) != ESP_OK) {
parser_data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
parser_data->status = PARSING_FAILED;
return ESP_FAIL;
}{...}
}{...} else if (parser_data->status == PARSING_HDR_VALUE) {
/* ... */
char *term_start = (char *)parser_data->last.at + parser_data->last.length;
memset(term_start, '\0', at - term_start);
parser_data->last.at = at;
parser_data->last.length = 0;
parser_data->status = PARSING_HDR_FIELD;
ra->req_hdrs_count++;
}{...} else if (parser_data->status != PARSING_HDR_FIELD) {
ESP_LOGE(TAG, LOG_FMT("unexpected state transition"));
parser_data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
parser_data->status = PARSING_FAILED;
return ESP_FAIL;
}{...}
ESP_LOGD(TAG, LOG_FMT("processing field = %.*s"), (int)length, at);
parser_data->last.length += length;
return ESP_OK;
}{ ... }
/* ... */
static esp_err_t cb_header_value(http_parser *parser, const char *at, size_t length)
{
parser_data_t *parser_data = (parser_data_t *) parser->data;
if (parser_data->status == PARSING_HDR_FIELD) {
parser_data->last.at = at;
parser_data->last.length = 0;
parser_data->status = PARSING_HDR_VALUE;
if (length == 0) {
/* ... */
char *at_adj = (char *)parser_data->last.at;
while (*(--at_adj) != ':');
while (*(++at_adj) == ' ');
parser_data->last.at = at_adj;
}{...}
}{...} else if (parser_data->status != PARSING_HDR_VALUE) {
ESP_LOGE(TAG, LOG_FMT("unexpected state transition"));
parser_data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
parser_data->status = PARSING_FAILED;
return ESP_FAIL;
}{...}
ESP_LOGD(TAG, LOG_FMT("processing value = %.*s"), (int)length, at);
parser_data->last.length += length;
return ESP_OK;
}{ ... }
/* ... */
static esp_err_t cb_headers_complete(http_parser *parser)
{
parser_data_t *parser_data = (parser_data_t *) parser->data;
struct httpd_req *r = parser_data->req;
struct httpd_req_aux *ra = r->aux;
if (parser_data->status == PARSING_URL) {
ESP_LOGD(TAG, LOG_FMT("no headers"));
if (verify_url(parser) != ESP_OK) {
/* ... */
parser_data->status = PARSING_FAILED;
return ESP_FAIL;
}{...}
}{...} else if (parser_data->status == PARSING_HDR_VALUE) {
char *at = (char *)parser_data->last.at + parser_data->last.length;
/* ... */
ssize_t remaining_length = parser_data->raw_datalen - (at - ra->scratch);
if (remaining_length < 2) {
ESP_LOGE(TAG, LOG_FMT("invalid length of data remaining to be parsed"));
parser_data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
parser_data->status = PARSING_FAILED;
return ESP_FAIL;
}{...}
/* ... */
unsigned short remaining_terminators = 2;
while (remaining_length-- && remaining_terminators) {
if (*at == '\n') {
remaining_terminators--;
}{...}
*(at++) = '\0';
}{...}
if (remaining_terminators) {
ESP_LOGE(TAG, LOG_FMT("incomplete termination of headers"));
parser_data->error = HTTPD_400_BAD_REQUEST;
parser_data->status = PARSING_FAILED;
return ESP_FAIL;
}{...}
parser_data->last.at = at;
ra->req_hdrs_count++;
}{...} else {
ESP_LOGE(TAG, LOG_FMT("unexpected state transition"));
parser_data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
parser_data->status = PARSING_FAILED;
return ESP_FAIL;
}{...}
r->content_len = ((int)parser->content_length != -1 ?
parser->content_length : 0);
ESP_LOGD(TAG, LOG_FMT("bytes read = %" PRId32 ""), parser->nread);
ESP_LOGD(TAG, LOG_FMT("content length = %"NEWLIB_NANO_COMPAT_FORMAT), NEWLIB_NANO_COMPAT_CAST(r->content_len));
if (parser->upgrade) {
#ifdef CONFIG_HTTPD_WS_SUPPORT
ESP_LOGD(TAG, LOG_FMT("Got an upgrade request"));
char ws_upgrade_hdr_val[] = "websocket";
if (httpd_req_get_hdr_value_str(r, "Upgrade", ws_upgrade_hdr_val, sizeof(ws_upgrade_hdr_val)) != ESP_OK) {
ESP_LOGW(TAG, LOG_FMT("Upgrade header does not match the length of \"websocket\""));
parser_data->error = HTTPD_400_BAD_REQUEST;
parser_data->status = PARSING_FAILED;
return ESP_FAIL;
}{...}
if (strcasecmp("websocket", ws_upgrade_hdr_val) != 0) {
ESP_LOGW(TAG, LOG_FMT("Upgrade header found but it's %s"), ws_upgrade_hdr_val);
parser_data->error = HTTPD_400_BAD_REQUEST;
parser_data->status = PARSING_FAILED;
return ESP_FAIL;
}{...}
ra->ws_handshake_detect = true;/* ... */
#else
ESP_LOGD(TAG, LOG_FMT("WS functions has been disabled, Upgrade request is not supported."));
parser_data->error = HTTPD_400_BAD_REQUEST;
parser_data->status = PARSING_FAILED;
return ESP_FAIL;/* ... */
#endif
}{...}
parser_data->status = PARSING_BODY;
ra->remaining_len = r->content_len;
esp_http_server_dispatch_event(HTTP_SERVER_EVENT_ON_HEADER, &(ra->sd->fd), sizeof(int));
return ESP_OK;
}{ ... }
/* ... */
static esp_err_t cb_on_body(http_parser *parser, const char *at, size_t length)
{
parser_data_t *parser_data = (parser_data_t *) parser->data;
if (parser_data->status != PARSING_BODY) {
ESP_LOGE(TAG, LOG_FMT("unexpected state transition"));
parser_data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
parser_data->status = PARSING_FAILED;
return ESP_FAIL;
}{...}
/* ... */
if (pause_parsing(parser, at) != ESP_OK) {
parser_data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
parser_data->status = PARSING_FAILED;
return ESP_FAIL;
}{...}
parser_data->last.at = 0;
parser_data->last.length = 0;
parser_data->status = PARSING_COMPLETE;
ESP_LOGD(TAG, LOG_FMT("body begins"));
return ESP_OK;
}{ ... }
/* ... */
static esp_err_t cb_no_body(http_parser *parser)
{
parser_data_t *parser_data = (parser_data_t *) parser->data;
if (parser_data->status == PARSING_URL) {
ESP_LOGD(TAG, LOG_FMT("no headers"));
if (verify_url(parser) != ESP_OK) {
/* ... */
parser_data->status = PARSING_FAILED;
return ESP_FAIL;
}{...}
}{...} else if (parser_data->status != PARSING_BODY) {
ESP_LOGE(TAG, LOG_FMT("unexpected state transition"));
parser_data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
parser_data->status = PARSING_FAILED;
return ESP_FAIL;
}{...}
/* ... */
if (pause_parsing(parser, parser_data->last.at) != ESP_OK) {
parser_data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
parser_data->status = PARSING_FAILED;
return ESP_FAIL;
}{...}
parser_data->last.at = 0;
parser_data->last.length = 0;
parser_data->status = PARSING_COMPLETE;
ESP_LOGD(TAG, LOG_FMT("message complete"));
return ESP_OK;
}{ ... }
static int read_block(httpd_req_t *req, size_t offset, size_t length)
{
struct httpd_req_aux *raux = req->aux;
ssize_t buf_len = MIN(length, (sizeof(raux->scratch) - offset));
if (buf_len <= 0) {
return 0;
}{...}
/* ... */
int nbytes = httpd_recv_with_opt(req, raux->scratch + offset, buf_len, true);
if (nbytes < 0) {
ESP_LOGD(TAG, LOG_FMT("error in httpd_recv"));
/* ... */
if (nbytes == HTTPD_SOCK_ERR_TIMEOUT) {
/* ... */
return (httpd_req_handle_err(req, HTTPD_408_REQ_TIMEOUT) == ESP_OK) ?
HTTPD_SOCK_ERR_TIMEOUT : HTTPD_SOCK_ERR_FAIL;
}{...}
/* ... */
return HTTPD_SOCK_ERR_FAIL;
}{...} else if (nbytes == 0) {
ESP_LOGD(TAG, LOG_FMT("connection closed"));
/* ... */
return HTTPD_SOCK_ERR_FAIL;
}{...}
ESP_LOGD(TAG, LOG_FMT("received HTTP request block size = %d"), nbytes);
return nbytes;
}{ ... }
static int parse_block(http_parser *parser, size_t offset, size_t length)
{
parser_data_t *data = (parser_data_t *)(parser->data);
httpd_req_t *req = data->req;
struct httpd_req_aux *raux = req->aux;
size_t nparsed = 0;
if (!length) {
/* ... */
ESP_LOGW(TAG, LOG_FMT("request URI/header too long"));
switch (data->status) {
case PARSING_URL:
data->error = HTTPD_414_URI_TOO_LONG;
break;...
case PARSING_HDR_FIELD:
case PARSING_HDR_VALUE:
data->error = HTTPD_431_REQ_HDR_FIELDS_TOO_LARGE;
break;...
default:
ESP_LOGE(TAG, LOG_FMT("unexpected state"));
data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
break;...
}{...}
data->status = PARSING_FAILED;
return -1;
}{...}
if (data->paused) {
nparsed = continue_parsing(parser, length);
length -= nparsed;
offset += nparsed;
if (!length) {
return nparsed;
}{...}
}{...}
nparsed = http_parser_execute(parser, &data->settings,
raux->scratch + offset, length);
if (data->status == PARSING_FAILED) {
/* ... */
ESP_LOGW(TAG, LOG_FMT("parsing failed"));
return -1;
}{...} else if (data->paused) {
/* ... */
data->pre_parsed -= (length - nparsed);
return 0;
}{...} else if (nparsed != length) {
data->error = HTTPD_400_BAD_REQUEST;
data->status = PARSING_FAILED;
ESP_LOGW(TAG, LOG_FMT("incomplete (%"NEWLIB_NANO_COMPAT_FORMAT"/%"NEWLIB_NANO_COMPAT_FORMAT") with parser error = %d"),
NEWLIB_NANO_COMPAT_CAST(nparsed), NEWLIB_NANO_COMPAT_CAST(length), parser->http_errno);
return -1;
}{...}
/* ... */
ESP_LOGD(TAG, LOG_FMT("parsed block size = %"NEWLIB_NANO_COMPAT_FORMAT), NEWLIB_NANO_COMPAT_CAST((offset + nparsed)));
return offset + nparsed;
}{ ... }
static void parse_init(httpd_req_t *r, http_parser *parser, parser_data_t *data)
{
memset(data, 0, sizeof(parser_data_t));
data->req = r;
http_parser_init(parser, HTTP_REQUEST);
parser->data = (void *)data;
http_parser_settings_init(&data->settings);
data->settings.on_url = cb_url;
data->settings.on_header_field = cb_header_field;
data->settings.on_header_value = cb_header_value;
data->settings.on_headers_complete = cb_headers_complete;
data->settings.on_body = cb_on_body;
data->settings.on_message_complete = cb_no_body;
}{ ... }
/* ... */
static esp_err_t httpd_parse_req(struct httpd_data *hd)
{
httpd_req_t *r = &hd->hd_req;
int blk_len, offset;
http_parser parser = {};
parser_data_t parser_data = {};
parse_init(r, &parser, &parser_data);
offset = 0;
do {
if ((blk_len = read_block(r, offset, PARSER_BLOCK_SIZE)) < 0) {
if (blk_len == HTTPD_SOCK_ERR_TIMEOUT) {
/* ... */
continue;
}{...}
/* ... */
return ESP_FAIL;
}{...}
/* ... */
parser_data.raw_datalen = blk_len + offset;
if ((offset = parse_block(&parser, offset, blk_len)) < 0) {
/* ... */
return httpd_req_handle_err(r, parser_data.error);
}{...}
}{...} while (parser_data.status != PARSING_COMPLETE);
ESP_LOGD(TAG, LOG_FMT("parsing complete"));
return httpd_uri(hd);
}{ ... }
static void init_req(httpd_req_t *r, httpd_config_t *config)
{
r->handle = 0;
r->method = 0;
memset((char*)r->uri, 0, sizeof(r->uri));
r->content_len = 0;
r->aux = 0;
r->user_ctx = 0;
r->sess_ctx = 0;
r->free_ctx = 0;
r->ignore_sess_ctx_changes = 0;
}{ ... }
static void init_req_aux(struct httpd_req_aux *ra, httpd_config_t *config)
{
ra->sd = 0;
memset(ra->scratch, 0, sizeof(ra->scratch));
ra->remaining_len = 0;
ra->status = 0;
ra->content_type = 0;
ra->first_chunk_sent = 0;
ra->req_hdrs_count = 0;
ra->resp_hdrs_count = 0;
#if CONFIG_HTTPD_WS_SUPPORT
ra->ws_handshake_detect = false;
#endif
memset(ra->resp_hdrs, 0, config->max_resp_headers * sizeof(struct resp_hdr));
}{ ... }
static void httpd_req_cleanup(httpd_req_t *r)
{
struct httpd_req_aux *ra = r->aux;
if ((r->ignore_sess_ctx_changes == false) && (ra->sd->ctx != r->sess_ctx)) {
httpd_sess_free_ctx(&ra->sd->ctx, ra->sd->free_ctx);
}{...}
#if CONFIG_HTTPD_WS_SUPPORT
if (ra->sd->ws_close) {
ESP_LOGD(TAG, LOG_FMT("Try closing WS connection at FD: %d"), ra->sd->fd);
httpd_sess_trigger_close(r->handle, ra->sd->fd);
}{...}
#endif/* ... */
ra->sd->ctx = r->sess_ctx;
ra->sd->free_ctx = r->free_ctx;
ra->sd->ignore_sess_ctx_changes = r->ignore_sess_ctx_changes;
ra->sd = NULL;
r->handle = NULL;
r->aux = NULL;
r->user_ctx = NULL;
}{ ... }
/* ... */
esp_err_t httpd_req_new(struct httpd_data *hd, struct sock_db *sd)
{
httpd_req_t *r = &hd->hd_req;
init_req(r, &hd->config);
init_req_aux(&hd->hd_req_aux, &hd->config);
r->handle = hd;
r->aux = &hd->hd_req_aux;
struct httpd_req_aux *ra = r->aux;
ra->sd = sd;
ra->status = (char *)HTTPD_200;
ra->content_type = (char *)HTTPD_TYPE_TEXT;
ra->first_chunk_sent = false;
r->sess_ctx = sd->ctx;
r->free_ctx = sd->free_ctx;
r->ignore_sess_ctx_changes = sd->ignore_sess_ctx_changes;
esp_err_t ret;
#ifdef CONFIG_HTTPD_WS_SUPPORT
r->user_ctx = sd->ws_user_ctx;
ESP_LOGD(TAG, LOG_FMT("New request, has WS? %s, sd->ws_handler valid? %s, sd->ws_close? %s"),
sd->ws_handshake_done ? "Yes" : "No",
sd->ws_handler != NULL ? "Yes" : "No",
sd->ws_close ? "Yes" : "No");
if (sd->ws_handshake_done && sd->ws_handler != NULL) {
if (sd->ws_close == true) {
ESP_LOGD(TAG, LOG_FMT("WS was marked close"));
return ESP_OK;
}{...}
ret = httpd_ws_get_frame_type(r);
ESP_LOGD(TAG, LOG_FMT("New WS request from existing socket, ws_type=%d"), ra->ws_type);
if (ra->ws_type == HTTPD_WS_TYPE_CLOSE) {
sd->ws_close = true;
}{...} else if (ra->ws_type == HTTPD_WS_TYPE_PONG) {
ESP_LOGD(TAG, LOG_FMT("Received PONG frame"));
}{...}
if (ret == ESP_OK &&
(ra->ws_type < HTTPD_WS_TYPE_CLOSE || sd->ws_control_frames)) {
ret = sd->ws_handler(r);
}{...}
if (ret != ESP_OK) {
httpd_req_cleanup(r);
}{...}
return ret;
}{...}
#endif/* ... */
ret = httpd_parse_req(hd);
if (ret != ESP_OK) {
httpd_req_cleanup(r);
}{...}
return ret;
}{ ... }
/* ... */
esp_err_t httpd_req_delete(struct httpd_data *hd)
{
httpd_req_t *r = &hd->hd_req;
struct httpd_req_aux *ra = r->aux;
while (ra->remaining_len) {
/* ... */
char dummy[CONFIG_HTTPD_PURGE_BUF_LEN];
int recv_len = MIN(sizeof(dummy), ra->remaining_len);
recv_len = httpd_req_recv(r, dummy, recv_len);
if (recv_len <= 0) {
httpd_req_cleanup(r);
return ESP_FAIL;
}{...}
ESP_LOGD(TAG, LOG_FMT("purging data size : %d bytes"), recv_len);
#ifdef CONFIG_HTTPD_LOG_PURGE_DATA
/* ... */
ESP_LOGD(TAG, "================= PURGED DATA =================");
ESP_LOG_BUFFER_HEX_LEVEL(TAG, dummy, recv_len, ESP_LOG_DEBUG);
ESP_LOGD(TAG, "===============================================");/* ... */
#endif
}{...}
httpd_req_cleanup(r);
return ESP_OK;
}{ ... }
/* ... */
bool httpd_validate_req_ptr(httpd_req_t *r)
{
if (r) {
struct httpd_data *hd = (struct httpd_data *) r->handle;
if (hd) {
/* ... */
if (httpd_os_thread_handle() == hd->hd_td.handle) {
return true;
}{...}
}{...}
}{...}
return false;
}{ ... }
esp_err_t httpd_query_key_value(const char *qry_str, const char *key, char *val, size_t val_size)
{
if (qry_str == NULL || key == NULL || val == NULL) {
return ESP_ERR_INVALID_ARG;
}{...}
const char *qry_ptr = qry_str;
const size_t buf_len = val_size;
while (strlen(qry_ptr)) {
/* ... */
const char *val_ptr = strchr(qry_ptr, '=');
if (!val_ptr) {
break;
}{...}
size_t offset = val_ptr - qry_ptr;
/* ... */
if ((offset != strlen(key)) ||
(strncasecmp(qry_ptr, key, offset))) {
/* ... */
qry_ptr = strchr(val_ptr, '&');
if (!qry_ptr) {
break;
}{...}
qry_ptr++;
continue;
}{...}
qry_ptr = strchr(++val_ptr, '&');
/* ... */
if (!qry_ptr) {
qry_ptr = val_ptr + strlen(val_ptr);
}{...}
val_size = qry_ptr - val_ptr + 1;
strlcpy(val, val_ptr, MIN(val_size, buf_len));
if (buf_len < val_size) {
return ESP_ERR_HTTPD_RESULT_TRUNC;
}{...}
return ESP_OK;
}{...}
ESP_LOGD(TAG, LOG_FMT("key %s not found"), key);
return ESP_ERR_NOT_FOUND;
}{ ... }
size_t httpd_req_get_url_query_len(httpd_req_t *r)
{
if (r == NULL) {
return 0;
}{...}
if (!httpd_valid_req(r)) {
return 0;
}{...}
if (r->uri[0] == '\0') {
ESP_LOGD(TAG, "uri is empty");
return 0;
}{...}
struct httpd_req_aux *ra = r->aux;
struct http_parser_url *res = &ra->url_parse_res;
if (res->field_set & (1 << UF_QUERY)) {
return res->field_data[UF_QUERY].len;
}{...}
return 0;
}{ ... }
esp_err_t httpd_req_get_url_query_str(httpd_req_t *r, char *buf, size_t buf_len)
{
if (r == NULL || buf == NULL) {
return ESP_ERR_INVALID_ARG;
}{...}
if (!httpd_valid_req(r)) {
return ESP_ERR_HTTPD_INVALID_REQ;
}{...}
if (r->uri[0] == '\0') {
ESP_LOGD(TAG, "uri is empty");
return ESP_FAIL;
}{...}
struct httpd_req_aux *ra = r->aux;
struct http_parser_url *res = &ra->url_parse_res;
if (res->field_set & (1 << UF_QUERY)) {
const char *qry = r->uri + res->field_data[UF_QUERY].off;
/* ... */
size_t min_buf_len = res->field_data[UF_QUERY].len + 1;
strlcpy(buf, qry, MIN(buf_len, min_buf_len));
if (buf_len < min_buf_len) {
return ESP_ERR_HTTPD_RESULT_TRUNC;
}{...}
return ESP_OK;
}{...}
return ESP_ERR_NOT_FOUND;
}{ ... }
size_t httpd_req_get_hdr_value_len(httpd_req_t *r, const char *field)
{
if (r == NULL || field == NULL) {
return 0;
}{...}
if (!httpd_valid_req(r)) {
return 0;
}{...}
struct httpd_req_aux *ra = r->aux;
const char *hdr_ptr = ra->scratch;
unsigned count = ra->req_hdrs_count;
while (count--) {
/* ... */
const char *val_ptr = strchr(hdr_ptr, ':');
if (!val_ptr) {
break;
}{...}
/* ... */
if ((val_ptr - hdr_ptr != strlen(field)) ||
(strncasecmp(hdr_ptr, field, strlen(field)))) {
if (count) {
hdr_ptr = 1 + strchr(hdr_ptr, '\0');
/* ... */
while (*hdr_ptr == '\0') {
hdr_ptr++;
}{...}
}{...}
continue;
}{...}
val_ptr++;
while ((*val_ptr != '\0') && (*val_ptr == ' ')) {
val_ptr++;
}{...}
return strlen(val_ptr);
}{...}
return 0;
}{ ... }
esp_err_t httpd_req_get_hdr_value_str(httpd_req_t *r, const char *field, char *val, size_t val_size)
{
if (r == NULL || field == NULL) {
return ESP_ERR_INVALID_ARG;
}{...}
if (!httpd_valid_req(r)) {
return ESP_ERR_HTTPD_INVALID_REQ;
}{...}
struct httpd_req_aux *ra = r->aux;
const char *hdr_ptr = ra->scratch;
unsigned count = ra->req_hdrs_count;
const size_t buf_len = val_size;
while (count--) {
/* ... */
const char *val_ptr = strchr(hdr_ptr, ':');
if (!val_ptr) {
break;
}{...}
/* ... */
if ((val_ptr - hdr_ptr != strlen(field)) ||
(strncasecmp(hdr_ptr, field, strlen(field)))) {
if (count) {
hdr_ptr = 1 + strchr(hdr_ptr, '\0');
/* ... */
while (*hdr_ptr == '\0') {
hdr_ptr++;
}{...}
}{...}
continue;
}{...}
val_ptr++;
while ((*val_ptr != '\0') && (*val_ptr == ' ')) {
val_ptr++;
}{...}
strlcpy(val, val_ptr, buf_len);
val_size = strlen(val_ptr) + 1;
if (buf_len < val_size) {
return ESP_ERR_HTTPD_RESULT_TRUNC;
}{...}
return ESP_OK;
}{...}
return ESP_ERR_NOT_FOUND;
}{ ... }
esp_err_t static httpd_cookie_key_value(const char *cookie_str, const char *key, char *val, size_t *val_size)
{
if (cookie_str == NULL || key == NULL || val == NULL) {
return ESP_ERR_INVALID_ARG;
}{...}
const char *cookie_ptr = cookie_str;
const size_t buf_len = *val_size;
size_t _val_size = *val_size;
while (strlen(cookie_ptr)) {
/* ... */
const char *val_ptr = strchr(cookie_ptr, '=');
if (!val_ptr) {
break;
}{...}
size_t offset = val_ptr - cookie_ptr;
/* ... */
if ((offset != strlen(key)) || (strncasecmp(cookie_ptr, key, offset) != 0)) {
/* ... */
cookie_ptr = strchr(val_ptr, ' ');
if (!cookie_ptr) {
break;
}{...}
cookie_ptr++;
continue;
}{...}
cookie_ptr = strchr(++val_ptr, ';');
/* ... */
if (!cookie_ptr) {
cookie_ptr = val_ptr + strlen(val_ptr);
}{...}
_val_size = cookie_ptr - val_ptr + 1;
strlcpy(val, val_ptr, MIN(_val_size, buf_len));
if (buf_len < _val_size) {
*val_size = _val_size;
return ESP_ERR_HTTPD_RESULT_TRUNC;
}{...}
*val_size = MIN(_val_size, buf_len);
return ESP_OK;
}{...}
ESP_LOGD(TAG, LOG_FMT("cookie %s not found"), key);
return ESP_ERR_NOT_FOUND;
}{ ... }
esp_err_t httpd_req_get_cookie_val(httpd_req_t *req, const char *cookie_name, char *val, size_t *val_size)
{
esp_err_t ret;
size_t hdr_len_cookie = httpd_req_get_hdr_value_len(req, "Cookie");
char *cookie_str = NULL;
if (hdr_len_cookie <= 0) {
return ESP_ERR_NOT_FOUND;
}{...}
cookie_str = malloc(hdr_len_cookie + 1);
if (cookie_str == NULL) {
ESP_LOGE(TAG, "Failed to allocate memory for cookie string");
return ESP_ERR_NO_MEM;
}{...}
if (httpd_req_get_hdr_value_str(req, "Cookie", cookie_str, hdr_len_cookie + 1) != ESP_OK) {
ESP_LOGW(TAG, "Cookie not found in header uri:[%s]", req->uri);
free(cookie_str);
return ESP_ERR_NOT_FOUND;
}{...}
ret = httpd_cookie_key_value(cookie_str, cookie_name, val, val_size);
free(cookie_str);
return ret;
}{ ... }