httpd_parse.c 27 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856
  1. // Copyright 2018 Espressif Systems (Shanghai) PTE LTD
  2. //
  3. // Licensed under the Apache License, Version 2.0 (the "License");
  4. // you may not use this file except in compliance with the License.
  5. // You may obtain a copy of the License at
  6. //
  7. // http://www.apache.org/licenses/LICENSE-2.0
  8. //
  9. // Unless required by applicable law or agreed to in writing, software
  10. // distributed under the License is distributed on an "AS IS" BASIS,
  11. // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
  12. // See the License for the specific language governing permissions and
  13. // limitations under the License.
  14. #include <stdlib.h>
  15. #include <sys/param.h>
  16. #include <esp_log.h>
  17. #include <esp_err.h>
  18. #include <http_parser.h>
  19. #include <esp_http_server.h>
  20. #include "esp_httpd_priv.h"
  21. #include "osal.h"
  22. static const char *TAG = "httpd_parse";
  23. typedef struct {
  24. /* Parser settings for http_parser_execute() */
  25. http_parser_settings settings;
  26. /* Request being parsed */
  27. struct httpd_req *req;
  28. /* Status of the parser describes the part of the
  29. * HTTP request packet being processed at any moment.
  30. */
  31. enum {
  32. PARSING_IDLE = 0,
  33. PARSING_URL,
  34. PARSING_HDR_FIELD,
  35. PARSING_HDR_VALUE,
  36. PARSING_BODY,
  37. PARSING_COMPLETE,
  38. PARSING_FAILED
  39. } status;
  40. /* Response error code in case of PARSING_FAILED */
  41. httpd_err_resp_t error;
  42. /* For storing last callback parameters */
  43. struct {
  44. const char *at;
  45. size_t length;
  46. } last;
  47. /* State variables */
  48. bool paused; /*!< Parser is paused */
  49. size_t pre_parsed; /*!< Length of data to be skipped while parsing */
  50. size_t raw_datalen; /*!< Full length of the raw data in scratch buffer */
  51. } parser_data_t;
  52. static esp_err_t verify_url (http_parser *parser)
  53. {
  54. parser_data_t *parser_data = (parser_data_t *) parser->data;
  55. struct httpd_req *r = parser_data->req;
  56. struct httpd_req_aux *ra = r->aux;
  57. struct http_parser_url *res = &ra->url_parse_res;
  58. /* Get previous values of the parser callback arguments */
  59. const char *at = parser_data->last.at;
  60. size_t length = parser_data->last.length;
  61. if ((r->method = parser->method) < 0) {
  62. ESP_LOGW(TAG, LOG_FMT("HTTP Operation not supported"));
  63. parser_data->error = HTTPD_501_METHOD_NOT_IMPLEMENTED;
  64. return ESP_FAIL;
  65. }
  66. if (sizeof(r->uri) < (length + 1)) {
  67. ESP_LOGW(TAG, LOG_FMT("URI length (%d) greater than supported (%d)"),
  68. length, sizeof(r->uri));
  69. parser_data->error = HTTPD_414_URI_TOO_LONG;
  70. parser_data->status = PARSING_FAILED;
  71. return ESP_FAIL;
  72. }
  73. /* Keep URI with terminating null character. Note URI string pointed
  74. * by 'at' is not NULL terminated, therefore use length provided by
  75. * parser while copying the URI to buffer */
  76. strlcpy((char *)r->uri, at, (length + 1));
  77. ESP_LOGD(TAG, LOG_FMT("received URI = %s"), r->uri);
  78. /* Make sure version is HTTP/1.1 */
  79. if ((parser->http_major != 1) && (parser->http_minor != 1)) {
  80. ESP_LOGW(TAG, LOG_FMT("unsupported HTTP version = %d.%d"),
  81. parser->http_major, parser->http_minor);
  82. parser_data->error = HTTPD_505_VERSION_NOT_SUPPORTED;
  83. return ESP_FAIL;
  84. }
  85. /* Parse URL and keep result for later */
  86. http_parser_url_init(res);
  87. if (http_parser_parse_url(r->uri, strlen(r->uri),
  88. r->method == HTTP_CONNECT, res)) {
  89. ESP_LOGW(TAG, LOG_FMT("http_parser_parse_url failed with errno = %d"),
  90. parser->http_errno);
  91. parser_data->error = HTTPD_400_BAD_REQUEST;
  92. return ESP_FAIL;
  93. }
  94. return ESP_OK;
  95. }
  96. /* http_parser callback on finding url in HTTP request
  97. * Will be invoked ATLEAST once every packet
  98. */
  99. static esp_err_t cb_url(http_parser *parser,
  100. const char *at, size_t length)
  101. {
  102. parser_data_t *parser_data = (parser_data_t *) parser->data;
  103. if (parser_data->status == PARSING_IDLE) {
  104. ESP_LOGD(TAG, LOG_FMT("message begin"));
  105. /* Store current values of the parser callback arguments */
  106. parser_data->last.at = at;
  107. parser_data->last.length = 0;
  108. parser_data->status = PARSING_URL;
  109. } else if (parser_data->status != PARSING_URL) {
  110. ESP_LOGE(TAG, LOG_FMT("unexpected state transition"));
  111. parser_data->status = PARSING_FAILED;
  112. return ESP_FAIL;
  113. }
  114. ESP_LOGD(TAG, LOG_FMT("processing url = %.*s"), length, at);
  115. /* Update length of URL string */
  116. if ((parser_data->last.length += length) > HTTPD_MAX_URI_LEN) {
  117. ESP_LOGW(TAG, LOG_FMT("URI length (%d) greater than supported (%d)"),
  118. parser_data->last.length, HTTPD_MAX_URI_LEN);
  119. parser_data->error = HTTPD_414_URI_TOO_LONG;
  120. parser_data->status = PARSING_FAILED;
  121. return ESP_FAIL;
  122. }
  123. return ESP_OK;
  124. }
  125. static esp_err_t pause_parsing(http_parser *parser, const char* at)
  126. {
  127. parser_data_t *parser_data = (parser_data_t *) parser->data;
  128. struct httpd_req *r = parser_data->req;
  129. struct httpd_req_aux *ra = r->aux;
  130. parser_data->pre_parsed = parser_data->raw_datalen
  131. - (at - ra->scratch);
  132. if (parser_data->pre_parsed != httpd_unrecv(r, at, parser_data->pre_parsed)) {
  133. ESP_LOGE(TAG, LOG_FMT("data too large for un-recv = %d"),
  134. parser_data->pre_parsed);
  135. return ESP_FAIL;
  136. }
  137. http_parser_pause(parser, 1);
  138. parser_data->paused = true;
  139. ESP_LOGD(TAG, LOG_FMT("paused"));
  140. return ESP_OK;
  141. }
  142. static size_t continue_parsing(http_parser *parser, size_t length)
  143. {
  144. parser_data_t *data = (parser_data_t *) parser->data;
  145. /* Part of the blk may have been parsed before
  146. * so we must skip that */
  147. length = MIN(length, data->pre_parsed);
  148. data->pre_parsed -= length;
  149. ESP_LOGD(TAG, LOG_FMT("skip pre-parsed data of size = %d"), length);
  150. http_parser_pause(parser, 0);
  151. data->paused = false;
  152. ESP_LOGD(TAG, LOG_FMT("un-paused"));
  153. return length;
  154. }
  155. /* http_parser callback on header field in HTTP request
  156. * May be invoked ATLEAST once every header field
  157. */
  158. static esp_err_t cb_header_field(http_parser *parser, const char *at, size_t length)
  159. {
  160. parser_data_t *parser_data = (parser_data_t *) parser->data;
  161. struct httpd_req *r = parser_data->req;
  162. struct httpd_req_aux *ra = r->aux;
  163. /* Check previous status */
  164. if (parser_data->status == PARSING_URL) {
  165. if (verify_url(parser) != ESP_OK) {
  166. parser_data->status = PARSING_FAILED;
  167. return ESP_FAIL;
  168. }
  169. ESP_LOGD(TAG, LOG_FMT("headers begin"));
  170. /* Last at is set to start of scratch where headers
  171. * will be received next */
  172. parser_data->last.at = ra->scratch;
  173. parser_data->last.length = 0;
  174. parser_data->status = PARSING_HDR_FIELD;
  175. /* Stop parsing for now and give control to process */
  176. if (pause_parsing(parser, at) != ESP_OK) {
  177. parser_data->status = PARSING_FAILED;
  178. return ESP_FAIL;
  179. }
  180. } else if (parser_data->status == PARSING_HDR_VALUE) {
  181. /* NULL terminate last header (key: value) pair */
  182. size_t offset = parser_data->last.at - ra->scratch;
  183. ra->scratch[offset + parser_data->last.length] = '\0';
  184. /* Store current values of the parser callback arguments */
  185. parser_data->last.at = at;
  186. parser_data->last.length = 0;
  187. parser_data->status = PARSING_HDR_FIELD;
  188. } else if (parser_data->status != PARSING_HDR_FIELD) {
  189. ESP_LOGE(TAG, LOG_FMT("unexpected state transition"));
  190. parser_data->status = PARSING_FAILED;
  191. return ESP_FAIL;
  192. }
  193. ESP_LOGD(TAG, LOG_FMT("processing field = %.*s"), length, at);
  194. /* Update length of header string */
  195. parser_data->last.length += length;
  196. return ESP_OK;
  197. }
  198. /* http_parser callback on header value in HTTP request.
  199. * May be invoked ATLEAST once every header value
  200. */
  201. static esp_err_t cb_header_value(http_parser *parser, const char *at, size_t length)
  202. {
  203. parser_data_t *parser_data = (parser_data_t *) parser->data;
  204. struct httpd_req *r = parser_data->req;
  205. struct httpd_req_aux *ra = r->aux;
  206. /* Check previous status */
  207. if (parser_data->status == PARSING_HDR_FIELD) {
  208. /* Store current values of the parser callback arguments */
  209. parser_data->last.at = at;
  210. parser_data->last.length = 0;
  211. parser_data->status = PARSING_HDR_VALUE;
  212. /* Increment header count */
  213. ra->req_hdrs_count++;
  214. } else if (parser_data->status != PARSING_HDR_VALUE) {
  215. ESP_LOGE(TAG, LOG_FMT("unexpected state transition"));
  216. parser_data->status = PARSING_FAILED;
  217. return ESP_FAIL;
  218. }
  219. ESP_LOGD(TAG, LOG_FMT("processing value = %.*s"), length, at);
  220. /* Update length of header string */
  221. parser_data->last.length += length;
  222. return ESP_OK;
  223. }
  224. /* http_parser callback on completing headers in HTTP request.
  225. * Will be invoked ONLY once every packet
  226. */
  227. static esp_err_t cb_headers_complete(http_parser *parser)
  228. {
  229. parser_data_t *parser_data = (parser_data_t *) parser->data;
  230. struct httpd_req *r = parser_data->req;
  231. struct httpd_req_aux *ra = r->aux;
  232. /* Check previous status */
  233. if (parser_data->status == PARSING_URL) {
  234. ESP_LOGD(TAG, LOG_FMT("no headers"));
  235. if (verify_url(parser) != ESP_OK) {
  236. parser_data->status = PARSING_FAILED;
  237. return ESP_FAIL;
  238. }
  239. } else if (parser_data->status == PARSING_HDR_VALUE) {
  240. /* NULL terminate last header (key: value) pair */
  241. size_t offset = parser_data->last.at - ra->scratch;
  242. ra->scratch[offset + parser_data->last.length] = '\0';
  243. /* Reach end of last header */
  244. parser_data->last.at += parser_data->last.length;
  245. } else {
  246. ESP_LOGE(TAG, LOG_FMT("unexpected state transition"));
  247. parser_data->status = PARSING_FAILED;
  248. return ESP_FAIL;
  249. }
  250. /* In absence of body/chunked encoding, http_parser sets content_len to -1 */
  251. r->content_len = ((int)parser->content_length != -1 ?
  252. parser->content_length : 0);
  253. ESP_LOGD(TAG, LOG_FMT("bytes read = %d"), parser->nread);
  254. ESP_LOGD(TAG, LOG_FMT("content length = %zu"), r->content_len);
  255. if (parser->upgrade) {
  256. ESP_LOGW(TAG, LOG_FMT("upgrade from HTTP not supported"));
  257. parser_data->error = HTTPD_XXX_UPGRADE_NOT_SUPPORTED;
  258. parser_data->status = PARSING_FAILED;
  259. return ESP_FAIL;
  260. }
  261. parser_data->status = PARSING_BODY;
  262. ra->remaining_len = r->content_len;
  263. return ESP_OK;
  264. }
  265. /* Last http_parser callback if body present in HTTP request.
  266. * Will be invoked ONLY once every packet
  267. */
  268. static esp_err_t cb_on_body(http_parser *parser, const char *at, size_t length)
  269. {
  270. parser_data_t *parser_data = (parser_data_t *) parser->data;
  271. /* Check previous status */
  272. if (parser_data->status != PARSING_BODY) {
  273. ESP_LOGE(TAG, LOG_FMT("unexpected state transition"));
  274. parser_data->status = PARSING_FAILED;
  275. return ESP_FAIL;
  276. }
  277. /* Pause parsing so that if part of another packet
  278. * is in queue then it doesn't get parsed, which
  279. * may reset the parser state and cause current
  280. * request packet to be lost */
  281. if (pause_parsing(parser, at) != ESP_OK) {
  282. parser_data->status = PARSING_FAILED;
  283. return ESP_FAIL;
  284. }
  285. parser_data->last.at = 0;
  286. parser_data->last.length = 0;
  287. parser_data->status = PARSING_COMPLETE;
  288. ESP_LOGD(TAG, LOG_FMT("body begins"));
  289. return ESP_OK;
  290. }
  291. /* Last http_parser callback if body absent in HTTP request.
  292. * Will be invoked ONLY once every packet
  293. */
  294. static esp_err_t cb_no_body(http_parser *parser)
  295. {
  296. parser_data_t *parser_data = (parser_data_t *) parser->data;
  297. const char* at = parser_data->last.at;
  298. /* Check previous status */
  299. if (parser_data->status == PARSING_URL) {
  300. ESP_LOGD(TAG, LOG_FMT("no headers"));
  301. if (verify_url(parser) != ESP_OK) {
  302. parser_data->status = PARSING_FAILED;
  303. return ESP_FAIL;
  304. }
  305. } else if (parser_data->status != PARSING_BODY) {
  306. ESP_LOGE(TAG, LOG_FMT("unexpected state transition"));
  307. parser_data->status = PARSING_FAILED;
  308. return ESP_FAIL;
  309. }
  310. /* Get end of packet */
  311. at += strlen("\r\n\r\n");
  312. /* Pause parsing so that if part of another packet
  313. * is in queue then it doesn't get parsed, which
  314. * may reset the parser state and cause current
  315. * request packet to be lost */
  316. if (pause_parsing(parser, at) != ESP_OK) {
  317. parser_data->status = PARSING_FAILED;
  318. return ESP_FAIL;
  319. }
  320. parser_data->last.at = 0;
  321. parser_data->last.length = 0;
  322. parser_data->status = PARSING_COMPLETE;
  323. ESP_LOGD(TAG, LOG_FMT("message complete"));
  324. return ESP_OK;
  325. }
  326. static int read_block(httpd_req_t *req, size_t offset, size_t length)
  327. {
  328. struct httpd_req_aux *raux = req->aux;
  329. /* Limits the read to scratch buffer size */
  330. size_t buf_len = MIN(length, (sizeof(raux->scratch) - offset));
  331. if (buf_len == 0) {
  332. return 0;
  333. }
  334. /* Receive data into buffer. If data is pending (from unrecv) then return
  335. * immediately after receiving pending data, as pending data may just complete
  336. * this request packet. */
  337. int nbytes = httpd_recv_with_opt(req, raux->scratch + offset, buf_len, true);
  338. if (nbytes < 0) {
  339. ESP_LOGD(TAG, LOG_FMT("error in httpd_recv"));
  340. if (nbytes == HTTPD_SOCK_ERR_TIMEOUT) {
  341. httpd_resp_send_err(req, HTTPD_408_REQ_TIMEOUT);
  342. }
  343. return -1;
  344. } else if (nbytes == 0) {
  345. ESP_LOGD(TAG, LOG_FMT("connection closed"));
  346. return -1;
  347. }
  348. ESP_LOGD(TAG, LOG_FMT("received HTTP request block size = %d"), nbytes);
  349. return nbytes;
  350. }
  351. static int parse_block(http_parser *parser, size_t offset, size_t length)
  352. {
  353. parser_data_t *data = (parser_data_t *)(parser->data);
  354. httpd_req_t *req = data->req;
  355. struct httpd_req_aux *raux = req->aux;
  356. size_t nparsed = 0;
  357. if (!length) {
  358. ESP_LOGW(TAG, LOG_FMT("response uri/header too big"));
  359. switch (data->status) {
  360. case PARSING_URL:
  361. data->error = HTTPD_414_URI_TOO_LONG;
  362. break;
  363. case PARSING_HDR_FIELD:
  364. case PARSING_HDR_VALUE:
  365. data->error = HTTPD_431_REQ_HDR_FIELDS_TOO_LARGE;
  366. default:
  367. break;
  368. }
  369. data->status = PARSING_FAILED;
  370. return -1;
  371. }
  372. /* Unpause the parsing if paused */
  373. if (data->paused) {
  374. nparsed = continue_parsing(parser, length);
  375. length -= nparsed;
  376. offset += nparsed;
  377. if (!length) {
  378. return nparsed;
  379. }
  380. }
  381. /* Execute http_parser */
  382. nparsed = http_parser_execute(parser, &data->settings,
  383. raux->scratch + offset, length);
  384. /* Check state */
  385. if (data->status == PARSING_FAILED) {
  386. ESP_LOGW(TAG, LOG_FMT("parsing failed"));
  387. return -1;
  388. } else if (data->paused) {
  389. /* Keep track of parsed data to be skipped
  390. * during next parsing cycle */
  391. data->pre_parsed -= (length - nparsed);
  392. return 0;
  393. } else if (nparsed != length) {
  394. /* http_parser error */
  395. data->status = PARSING_FAILED;
  396. data->error = HTTPD_400_BAD_REQUEST;
  397. ESP_LOGW(TAG, LOG_FMT("incomplete (%d/%d) with parser error = %d"),
  398. nparsed, length, parser->http_errno);
  399. return -1;
  400. }
  401. /* Continue parsing this section of HTTP request packet */
  402. ESP_LOGD(TAG, LOG_FMT("parsed block size = %d"), offset + nparsed);
  403. return offset + nparsed;
  404. }
  405. static void parse_init(httpd_req_t *r, http_parser *parser, parser_data_t *data)
  406. {
  407. /* Initialize parser data */
  408. memset(data, 0, sizeof(parser_data_t));
  409. data->req = r;
  410. /* Initialize parser */
  411. http_parser_init(parser, HTTP_REQUEST);
  412. parser->data = (void *)data;
  413. /* Initialize parser settings */
  414. http_parser_settings_init(&data->settings);
  415. /* Set parser callbacks */
  416. data->settings.on_url = cb_url;
  417. data->settings.on_header_field = cb_header_field;
  418. data->settings.on_header_value = cb_header_value;
  419. data->settings.on_headers_complete = cb_headers_complete;
  420. data->settings.on_body = cb_on_body;
  421. data->settings.on_message_complete = cb_no_body;
  422. }
  423. /* Function that receives TCP data and runs parser on it
  424. */
  425. static esp_err_t httpd_parse_req(struct httpd_data *hd)
  426. {
  427. httpd_req_t *r = &hd->hd_req;
  428. int blk_len, offset;
  429. http_parser parser;
  430. parser_data_t parser_data;
  431. /* Initialize parser */
  432. parse_init(r, &parser, &parser_data);
  433. /* Set offset to start of scratch buffer */
  434. offset = 0;
  435. do {
  436. /* Read block into scratch buffer */
  437. if ((blk_len = read_block(r, offset, PARSER_BLOCK_SIZE)) < 0) {
  438. /* Return error to close socket */
  439. return ESP_FAIL;
  440. }
  441. /* This is used by the callbacks to track
  442. * data usage of the buffer */
  443. parser_data.raw_datalen = blk_len + offset;
  444. /* Parse data block from buffer */
  445. if ((offset = parse_block(&parser, offset, blk_len)) < 0) {
  446. /* Server/Client error. Send error code as response status */
  447. return httpd_resp_send_err(r, parser_data.error);
  448. }
  449. } while (parser_data.status != PARSING_COMPLETE);
  450. ESP_LOGD(TAG, LOG_FMT("parsing complete"));
  451. return httpd_uri(hd);
  452. }
  453. static void init_req(httpd_req_t *r, httpd_config_t *config)
  454. {
  455. r->handle = 0;
  456. r->method = 0;
  457. memset((char*)r->uri, 0, sizeof(r->uri));
  458. r->content_len = 0;
  459. r->aux = 0;
  460. r->user_ctx = 0;
  461. r->sess_ctx = 0;
  462. r->free_ctx = 0;
  463. }
  464. static void init_req_aux(struct httpd_req_aux *ra, httpd_config_t *config)
  465. {
  466. ra->sd = 0;
  467. memset(ra->scratch, 0, sizeof(ra->scratch));
  468. ra->remaining_len = 0;
  469. ra->status = 0;
  470. ra->content_type = 0;
  471. ra->first_chunk_sent = 0;
  472. ra->req_hdrs_count = 0;
  473. ra->resp_hdrs_count = 0;
  474. memset(ra->resp_hdrs, 0, config->max_resp_headers * sizeof(struct resp_hdr));
  475. }
  476. static void httpd_req_cleanup(httpd_req_t *r)
  477. {
  478. struct httpd_req_aux *ra = r->aux;
  479. /* Retrieve session info from the request into the socket database */
  480. if (ra->sd->ctx != r->sess_ctx) {
  481. /* Free previous context */
  482. httpd_sess_free_ctx(ra->sd->ctx, ra->sd->free_ctx);
  483. ra->sd->ctx = r->sess_ctx;
  484. }
  485. ra->sd->free_ctx = r->free_ctx;
  486. /* Clear out the request and request_aux structures */
  487. ra->sd = NULL;
  488. r->handle = NULL;
  489. r->aux = NULL;
  490. }
  491. /* Function that processes incoming TCP data and
  492. * updates the http request data httpd_req_t
  493. */
  494. esp_err_t httpd_req_new(struct httpd_data *hd, struct sock_db *sd)
  495. {
  496. httpd_req_t *r = &hd->hd_req;
  497. init_req(r, &hd->config);
  498. init_req_aux(&hd->hd_req_aux, &hd->config);
  499. r->handle = hd;
  500. r->aux = &hd->hd_req_aux;
  501. /* Associate the request to the socket */
  502. struct httpd_req_aux *ra = r->aux;
  503. ra->sd = sd;
  504. /* Set defaults */
  505. ra->status = (char *)HTTPD_200;
  506. ra->content_type = (char *)HTTPD_TYPE_TEXT;
  507. ra->first_chunk_sent = false;
  508. /* Copy session info to the request */
  509. r->sess_ctx = sd->ctx;
  510. r->free_ctx = sd->free_ctx;
  511. /* Parse request */
  512. esp_err_t err = httpd_parse_req(hd);
  513. if (err != ESP_OK) {
  514. httpd_req_cleanup(r);
  515. }
  516. return err;
  517. }
  518. /* Function that resets the http request data
  519. */
  520. esp_err_t httpd_req_delete(struct httpd_data *hd)
  521. {
  522. httpd_req_t *r = &hd->hd_req;
  523. struct httpd_req_aux *ra = r->aux;
  524. /* Finish off reading any pending/leftover data */
  525. while (ra->remaining_len) {
  526. /* Any length small enough not to overload the stack, but large
  527. * enough to finish off the buffers fast
  528. */
  529. char dummy[32];
  530. int recv_len = MIN(sizeof(dummy) - 1, ra->remaining_len);
  531. int ret = httpd_req_recv(r, dummy, recv_len);
  532. if (ret < 0) {
  533. httpd_req_cleanup(r);
  534. return ESP_FAIL;
  535. }
  536. dummy[ret] = '\0';
  537. ESP_LOGD(TAG, LOG_FMT("purging data : %s"), dummy);
  538. }
  539. httpd_req_cleanup(r);
  540. return ESP_OK;
  541. }
  542. /* Validates the request to prevent users from calling APIs, that are to
  543. * be called only inside URI handler, outside the handler context
  544. */
  545. bool httpd_validate_req_ptr(httpd_req_t *r)
  546. {
  547. if (r) {
  548. struct httpd_data *hd = (struct httpd_data *) r->handle;
  549. if (hd) {
  550. /* Check if this function is running in the context of
  551. * the correct httpd server thread */
  552. if (httpd_os_thread_handle() == hd->hd_td.handle) {
  553. return true;
  554. }
  555. }
  556. }
  557. return false;
  558. }
  559. /* Helper function to get a URL query tag from a query string of the type param1=val1&param2=val2 */
  560. esp_err_t httpd_query_key_value(const char *qry_str, const char *key, char *val, size_t val_size)
  561. {
  562. if (qry_str == NULL || key == NULL || val == NULL) {
  563. return ESP_ERR_INVALID_ARG;
  564. }
  565. const char *qry_ptr = qry_str;
  566. const size_t buf_len = val_size;
  567. while (strlen(qry_ptr)) {
  568. /* Search for the '=' character. Else, it would mean
  569. * that the parameter is invalid */
  570. const char *val_ptr = strchr(qry_ptr, '=');
  571. if (!val_ptr) {
  572. break;
  573. }
  574. size_t offset = val_ptr - qry_ptr;
  575. /* If the key, does not match, continue searching.
  576. * Compare lengths first as key from url is not
  577. * null terminated (has '=' in the end) */
  578. if ((offset != strlen(key)) ||
  579. (strncasecmp(qry_ptr, key, offset))) {
  580. /* Get the name=val string. Multiple name=value pairs
  581. * are separated by '&' */
  582. qry_ptr = strchr(val_ptr, '&');
  583. if (!qry_ptr) {
  584. break;
  585. }
  586. qry_ptr++;
  587. continue;
  588. }
  589. /* Locate start of next query */
  590. qry_ptr = strchr(++val_ptr, '&');
  591. /* Or this could be the last query, in which
  592. * case get to the end of query string */
  593. if (!qry_ptr) {
  594. qry_ptr = val_ptr + strlen(val_ptr);
  595. }
  596. /* Update value length, including one byte for null */
  597. val_size = qry_ptr - val_ptr + 1;
  598. /* Copy value to the caller's buffer. */
  599. strlcpy(val, val_ptr, MIN(val_size, buf_len));
  600. /* If buffer length is smaller than needed, return truncation error */
  601. if (buf_len < val_size) {
  602. return ESP_ERR_HTTPD_RESULT_TRUNC;
  603. }
  604. return ESP_OK;
  605. }
  606. ESP_LOGD(TAG, LOG_FMT("key %s not found"), key);
  607. return ESP_ERR_NOT_FOUND;
  608. }
  609. size_t httpd_req_get_url_query_len(httpd_req_t *r)
  610. {
  611. if (r == NULL) {
  612. return 0;
  613. }
  614. if (!httpd_valid_req(r)) {
  615. return 0;
  616. }
  617. struct httpd_req_aux *ra = r->aux;
  618. struct http_parser_url *res = &ra->url_parse_res;
  619. /* Check if query field is present in the URL */
  620. if (res->field_set & (1 << UF_QUERY)) {
  621. return res->field_data[UF_QUERY].len;
  622. }
  623. return 0;
  624. }
  625. esp_err_t httpd_req_get_url_query_str(httpd_req_t *r, char *buf, size_t buf_len)
  626. {
  627. if (r == NULL || buf == NULL) {
  628. return ESP_ERR_INVALID_ARG;
  629. }
  630. if (!httpd_valid_req(r)) {
  631. return ESP_ERR_HTTPD_INVALID_REQ;
  632. }
  633. struct httpd_req_aux *ra = r->aux;
  634. struct http_parser_url *res = &ra->url_parse_res;
  635. /* Check if query field is present in the URL */
  636. if (res->field_set & (1 << UF_QUERY)) {
  637. const char *qry = r->uri + res->field_data[UF_QUERY].off;
  638. /* Minimum required buffer len for keeping
  639. * null terminated query string */
  640. size_t min_buf_len = res->field_data[UF_QUERY].len + 1;
  641. strlcpy(buf, qry, MIN(buf_len, min_buf_len));
  642. if (buf_len < min_buf_len) {
  643. return ESP_ERR_HTTPD_RESULT_TRUNC;
  644. }
  645. return ESP_OK;
  646. }
  647. return ESP_ERR_NOT_FOUND;
  648. }
  649. /* Get the length of the value string of a header request field */
  650. size_t httpd_req_get_hdr_value_len(httpd_req_t *r, const char *field)
  651. {
  652. if (r == NULL || field == NULL) {
  653. return 0;
  654. }
  655. if (!httpd_valid_req(r)) {
  656. return 0;
  657. }
  658. struct httpd_req_aux *ra = r->aux;
  659. const char *hdr_ptr = ra->scratch; /*!< Request headers are kept in scratch buffer */
  660. unsigned count = ra->req_hdrs_count; /*!< Count set during parsing */
  661. while (count--) {
  662. /* Search for the ':' character. Else, it would mean
  663. * that the field is invalid
  664. */
  665. const char *val_ptr = strchr(hdr_ptr, ':');
  666. if (!val_ptr) {
  667. break;
  668. }
  669. /* If the field, does not match, continue searching.
  670. * Compare lengths first as field from header is not
  671. * null terminated (has ':' in the end).
  672. */
  673. if ((val_ptr - hdr_ptr != strlen(field)) ||
  674. (strncasecmp(hdr_ptr, field, strlen(field)))) {
  675. hdr_ptr += strlen(hdr_ptr) + strlen("\r\n");
  676. continue;
  677. }
  678. /* Skip ':' */
  679. val_ptr++;
  680. /* Skip preceding space */
  681. while ((*val_ptr != '\0') && (*val_ptr == ' ')) {
  682. val_ptr++;
  683. }
  684. return strlen(val_ptr);
  685. }
  686. return 0;
  687. }
  688. /* Get the value of a field from the request headers */
  689. esp_err_t httpd_req_get_hdr_value_str(httpd_req_t *r, const char *field, char *val, size_t val_size)
  690. {
  691. if (r == NULL || field == NULL) {
  692. return ESP_ERR_INVALID_ARG;
  693. }
  694. if (!httpd_valid_req(r)) {
  695. return ESP_ERR_HTTPD_INVALID_REQ;
  696. }
  697. struct httpd_req_aux *ra = r->aux;
  698. const char *hdr_ptr = ra->scratch; /*!< Request headers are kept in scratch buffer */
  699. unsigned count = ra->req_hdrs_count; /*!< Count set during parsing */
  700. const size_t buf_len = val_size;
  701. while (count--) {
  702. /* Search for the ':' character. Else, it would mean
  703. * that the field is invalid
  704. */
  705. const char *val_ptr = strchr(hdr_ptr, ':');
  706. if (!val_ptr) {
  707. break;
  708. }
  709. /* If the field, does not match, continue searching.
  710. * Compare lengths first as field from header is not
  711. * null terminated (has ':' in the end).
  712. */
  713. if ((val_ptr - hdr_ptr != strlen(field)) ||
  714. (strncasecmp(hdr_ptr, field, strlen(field)))) {
  715. hdr_ptr += strlen(hdr_ptr) + strlen("\r\n");
  716. continue;
  717. }
  718. /* Skip ':' */
  719. val_ptr++;
  720. /* Skip preceding space */
  721. while ((*val_ptr != '\0') && (*val_ptr == ' ')) {
  722. val_ptr++;
  723. }
  724. /* Get the NULL terminated value and copy it to the caller's buffer. */
  725. strlcpy(val, val_ptr, buf_len);
  726. /* Update value length, including one byte for null */
  727. val_size = strlen(val_ptr) + 1;
  728. /* If buffer length is smaller than needed, return truncation error */
  729. if (buf_len < val_size) {
  730. return ESP_ERR_HTTPD_RESULT_TRUNC;
  731. }
  732. return ESP_OK;
  733. }
  734. return ESP_ERR_NOT_FOUND;
  735. }