/ components / esp_http_server / src / httpd_parse.c
httpd_parse.c
   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  
  15  
  16  #include <stdlib.h>
  17  #include <sys/param.h>
  18  #include <esp_log.h>
  19  #include <esp_err.h>
  20  #include <http_parser.h>
  21  
  22  #include <esp_http_server.h>
  23  #include "esp_httpd_priv.h"
  24  #include "osal.h"
  25  
  26  static const char *TAG = "httpd_parse";
  27  
  28  typedef struct {
  29      /* Parser settings for http_parser_execute() */
  30      http_parser_settings settings;
  31  
  32      /* Request being parsed */
  33      struct httpd_req *req;
  34  
  35      /* Status of the parser describes the part of the
  36       * HTTP request packet being processed at any moment.
  37       */
  38      enum {
  39          PARSING_IDLE = 0,
  40          PARSING_URL,
  41          PARSING_HDR_FIELD,
  42          PARSING_HDR_VALUE,
  43          PARSING_BODY,
  44          PARSING_COMPLETE,
  45          PARSING_FAILED
  46      } status;
  47  
  48      /* Response error code in case of PARSING_FAILED */
  49      httpd_err_code_t error;
  50  
  51      /* For storing last callback parameters */
  52      struct {
  53          const char *at;
  54          size_t      length;
  55      } last;
  56  
  57      /* State variables */
  58      bool   paused;          /*!< Parser is paused */
  59      size_t pre_parsed;      /*!< Length of data to be skipped while parsing */
  60      size_t raw_datalen;     /*!< Full length of the raw data in scratch buffer */
  61  } parser_data_t;
  62  
  63  static esp_err_t verify_url (http_parser *parser)
  64  {
  65      parser_data_t *parser_data  = (parser_data_t *) parser->data;
  66      struct httpd_req *r         = parser_data->req;
  67      struct httpd_req_aux *ra    = r->aux;
  68      struct http_parser_url *res = &ra->url_parse_res;
  69  
  70      /* Get previous values of the parser callback arguments */
  71      const char *at = parser_data->last.at;
  72      size_t  length = parser_data->last.length;
  73  
  74      if ((r->method = parser->method) < 0) {
  75          ESP_LOGW(TAG, LOG_FMT("HTTP Operation not supported"));
  76          parser_data->error = HTTPD_501_METHOD_NOT_IMPLEMENTED;
  77          return ESP_FAIL;
  78      }
  79  
  80      if (sizeof(r->uri) < (length + 1)) {
  81          ESP_LOGW(TAG, LOG_FMT("URI length (%d) greater than supported (%d)"),
  82                   length, sizeof(r->uri));
  83          parser_data->error = HTTPD_414_URI_TOO_LONG;
  84          return ESP_FAIL;
  85      }
  86  
  87      /* Keep URI with terminating null character. Note URI string pointed
  88       * by 'at' is not NULL terminated, therefore use length provided by
  89       * parser while copying the URI to buffer */
  90      strlcpy((char *)r->uri, at, (length + 1));
  91      ESP_LOGD(TAG, LOG_FMT("received URI = %s"), r->uri);
  92  
  93      /* Make sure version is HTTP/1.1 */
  94      if ((parser->http_major != 1) && (parser->http_minor != 1)) {
  95          ESP_LOGW(TAG, LOG_FMT("unsupported HTTP version = %d.%d"),
  96                   parser->http_major, parser->http_minor);
  97          parser_data->error = HTTPD_505_VERSION_NOT_SUPPORTED;
  98          return ESP_FAIL;
  99      }
 100  
 101      /* Parse URL and keep result for later */
 102      http_parser_url_init(res);
 103      if (http_parser_parse_url(r->uri, strlen(r->uri),
 104                                r->method == HTTP_CONNECT, res)) {
 105          ESP_LOGW(TAG, LOG_FMT("http_parser_parse_url failed with errno = %d"),
 106                                parser->http_errno);
 107          parser_data->error = HTTPD_400_BAD_REQUEST;
 108          return ESP_FAIL;
 109      }
 110      return ESP_OK;
 111  }
 112  
 113  /* http_parser callback on finding url in HTTP request
 114   * Will be invoked ATLEAST once every packet
 115   */
 116  static esp_err_t cb_url(http_parser *parser,
 117                          const char *at, size_t length)
 118  {
 119      parser_data_t *parser_data = (parser_data_t *) parser->data;
 120  
 121      if (parser_data->status == PARSING_IDLE) {
 122          ESP_LOGD(TAG, LOG_FMT("message begin"));
 123  
 124          /* Store current values of the parser callback arguments */
 125          parser_data->last.at     = at;
 126          parser_data->last.length = 0;
 127          parser_data->status      = PARSING_URL;
 128      } else if (parser_data->status != PARSING_URL) {
 129          ESP_LOGE(TAG, LOG_FMT("unexpected state transition"));
 130          parser_data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
 131          parser_data->status = PARSING_FAILED;
 132          return ESP_FAIL;
 133      }
 134  
 135      ESP_LOGD(TAG, LOG_FMT("processing url = %.*s"), length, at);
 136  
 137      /* Update length of URL string */
 138      if ((parser_data->last.length += length) > HTTPD_MAX_URI_LEN) {
 139          ESP_LOGW(TAG, LOG_FMT("URI length (%d) greater than supported (%d)"),
 140                   parser_data->last.length, HTTPD_MAX_URI_LEN);
 141          parser_data->error = HTTPD_414_URI_TOO_LONG;
 142          parser_data->status = PARSING_FAILED;
 143          return ESP_FAIL;
 144      }
 145      return ESP_OK;
 146  }
 147  
 148  static esp_err_t pause_parsing(http_parser *parser, const char* at)
 149  {
 150      parser_data_t *parser_data = (parser_data_t *) parser->data;
 151      struct httpd_req *r        = parser_data->req;
 152      struct httpd_req_aux *ra   = r->aux;
 153  
 154      /* The length of data that was not parsed due to interruption
 155       * and hence needs to be read again later for parsing */
 156      ssize_t unparsed = parser_data->raw_datalen - (at - ra->scratch);
 157      if (unparsed < 0) {
 158          ESP_LOGE(TAG, LOG_FMT("parsing beyond valid data = %d"), -unparsed);
 159          return ESP_ERR_INVALID_STATE;
 160      }
 161  
 162      /* Push back the un-parsed data into pending buffer for
 163       * receiving again with httpd_recv_with_opt() later when
 164       * read_block() executes */
 165      if (unparsed && (unparsed != httpd_unrecv(r, at, unparsed))) {
 166          ESP_LOGE(TAG, LOG_FMT("data too large for un-recv = %d"), unparsed);
 167          return ESP_FAIL;
 168      }
 169  
 170      /* Signal http_parser to pause execution and save the maximum
 171       * possible length, of the yet un-parsed data, that may get
 172       * parsed before http_parser_execute() returns. This pre_parsed
 173       * length will be updated then to reflect the actual length
 174       * that got parsed, and must be skipped when parsing resumes */
 175      parser_data->pre_parsed = unparsed;
 176      http_parser_pause(parser, 1);
 177      parser_data->paused = true;
 178      ESP_LOGD(TAG, LOG_FMT("paused"));
 179      return ESP_OK;
 180  }
 181  
 182  static size_t continue_parsing(http_parser *parser, size_t length)
 183  {
 184      parser_data_t *data = (parser_data_t *) parser->data;
 185  
 186      /* Part of the received data may have been parsed earlier
 187       * so we must skip that before parsing resumes */
 188      length = MIN(length, data->pre_parsed);
 189      data->pre_parsed -= length;
 190      ESP_LOGD(TAG, LOG_FMT("skip pre-parsed data of size = %d"), length);
 191  
 192      http_parser_pause(parser, 0);
 193      data->paused = false;
 194      ESP_LOGD(TAG, LOG_FMT("un-paused"));
 195      return length;
 196  }
 197  
 198  /* http_parser callback on header field in HTTP request
 199   * May be invoked ATLEAST once every header field
 200   */
 201  static esp_err_t cb_header_field(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  
 207      /* Check previous status */
 208      if (parser_data->status == PARSING_URL) {
 209          if (verify_url(parser) != ESP_OK) {
 210              /* verify_url would already have set the
 211               * error field of parser data, so only setting
 212               * status to failed */
 213              parser_data->status = PARSING_FAILED;
 214              return ESP_FAIL;
 215          }
 216  
 217          ESP_LOGD(TAG, LOG_FMT("headers begin"));
 218          /* Last at is set to start of scratch where headers
 219           * will be received next */
 220          parser_data->last.at     = ra->scratch;
 221          parser_data->last.length = 0;
 222          parser_data->status      = PARSING_HDR_FIELD;
 223  
 224          /* Stop parsing for now and give control to process */
 225          if (pause_parsing(parser, at) != ESP_OK) {
 226              parser_data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
 227              parser_data->status = PARSING_FAILED;
 228              return ESP_FAIL;
 229          }
 230      } else if (parser_data->status == PARSING_HDR_VALUE) {
 231          /* Overwrite terminator (CRLFs) following last header
 232           * (key: value) pair with null characters */
 233          char *term_start = (char *)parser_data->last.at + parser_data->last.length;
 234          memset(term_start, '\0', at - term_start);
 235  
 236          /* Store current values of the parser callback arguments */
 237          parser_data->last.at     = at;
 238          parser_data->last.length = 0;
 239          parser_data->status      = PARSING_HDR_FIELD;
 240  
 241          /* Increment header count */
 242          ra->req_hdrs_count++;
 243      } else if (parser_data->status != PARSING_HDR_FIELD) {
 244          ESP_LOGE(TAG, LOG_FMT("unexpected state transition"));
 245          parser_data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
 246          parser_data->status = PARSING_FAILED;
 247          return ESP_FAIL;
 248      }
 249  
 250      ESP_LOGD(TAG, LOG_FMT("processing field = %.*s"), length, at);
 251  
 252      /* Update length of header string */
 253      parser_data->last.length += length;
 254      return ESP_OK;
 255  }
 256  
 257  /* http_parser callback on header value in HTTP request.
 258   * May be invoked ATLEAST once every header value
 259   */
 260  static esp_err_t cb_header_value(http_parser *parser, const char *at, size_t length)
 261  {
 262      parser_data_t *parser_data = (parser_data_t *) parser->data;
 263  
 264      /* Check previous status */
 265      if (parser_data->status == PARSING_HDR_FIELD) {
 266          /* Store current values of the parser callback arguments */
 267          parser_data->last.at     = at;
 268          parser_data->last.length = 0;
 269          parser_data->status      = PARSING_HDR_VALUE;
 270  
 271          if (length == 0) {
 272              /* As per behavior of http_parser, when length > 0,
 273               * `at` points to the start of CRLF. But, in the
 274               * case when header value is empty (zero length),
 275               * then `at` points to the position right after
 276               * the CRLF. Since for our purpose we need `last.at`
 277               * to point to exactly where the CRLF starts, it
 278               * needs to be adjusted by the right offset */
 279              char *at_adj = (char *)parser_data->last.at;
 280              /* Find the end of header field string */
 281              while (*(--at_adj) != ':');
 282              /* Now skip leading spaces' */
 283              while (*(++at_adj) == ' ');
 284              /* Now we are at the right position */
 285              parser_data->last.at = at_adj;
 286          }
 287      } else if (parser_data->status != PARSING_HDR_VALUE) {
 288          ESP_LOGE(TAG, LOG_FMT("unexpected state transition"));
 289          parser_data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
 290          parser_data->status = PARSING_FAILED;
 291          return ESP_FAIL;
 292      }
 293  
 294      ESP_LOGD(TAG, LOG_FMT("processing value = %.*s"), length, at);
 295  
 296      /* Update length of header string */
 297      parser_data->last.length += length;
 298      return ESP_OK;
 299  }
 300  
 301  /* http_parser callback on completing headers in HTTP request.
 302   * Will be invoked ONLY once every packet
 303   */
 304  static esp_err_t cb_headers_complete(http_parser *parser)
 305  {
 306      parser_data_t *parser_data = (parser_data_t *) parser->data;
 307      struct httpd_req *r        = parser_data->req;
 308      struct httpd_req_aux *ra   = r->aux;
 309  
 310      /* Check previous status */
 311      if (parser_data->status == PARSING_URL) {
 312          ESP_LOGD(TAG, LOG_FMT("no headers"));
 313          if (verify_url(parser) != ESP_OK) {
 314              /* verify_url would already have set the
 315               * error field of parser data, so only setting
 316               * status to failed */
 317              parser_data->status = PARSING_FAILED;
 318              return ESP_FAIL;
 319          }
 320      } else if (parser_data->status == PARSING_HDR_VALUE) {
 321          /* Locate end of last header */
 322          char *at = (char *)parser_data->last.at + parser_data->last.length;
 323  
 324          /* Check if there is data left to parse. This value should
 325           * at least be equal to the number of line terminators, i.e. 2 */
 326          ssize_t remaining_length = parser_data->raw_datalen - (at - ra->scratch);
 327          if (remaining_length < 2) {
 328              ESP_LOGE(TAG, LOG_FMT("invalid length of data remaining to be parsed"));
 329              parser_data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
 330              parser_data->status = PARSING_FAILED;
 331              return ESP_FAIL;
 332          }
 333  
 334          /* Locate end of headers section by skipping the remaining
 335           * two line terminators. No assumption is made here about the
 336           * termination sequence used apart from the necessity that it
 337           * must end with an LF, because:
 338           *      1) some clients may send non standard LFs instead of
 339           *         CRLFs for indicating termination.
 340           *      2) it is the responsibility of http_parser to check
 341           *         that the termination is either CRLF or LF and
 342           *         not any other sequence */
 343          unsigned short remaining_terminators = 2;
 344          while (remaining_length-- && remaining_terminators) {
 345              if (*at == '\n') {
 346                  remaining_terminators--;
 347              }
 348              /* Overwrite termination characters with null */
 349              *(at++) = '\0';
 350          }
 351          if (remaining_terminators) {
 352              ESP_LOGE(TAG, LOG_FMT("incomplete termination of headers"));
 353              parser_data->error = HTTPD_400_BAD_REQUEST;
 354              parser_data->status = PARSING_FAILED;
 355              return ESP_FAIL;
 356          }
 357  
 358          /* Place the parser ptr right after the end of headers section */
 359          parser_data->last.at = at;
 360  
 361          /* Increment header count */
 362          ra->req_hdrs_count++;
 363      } else {
 364          ESP_LOGE(TAG, LOG_FMT("unexpected state transition"));
 365          parser_data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
 366          parser_data->status = PARSING_FAILED;
 367          return ESP_FAIL;
 368      }
 369  
 370      /* In absence of body/chunked encoding, http_parser sets content_len to -1 */
 371      r->content_len = ((int)parser->content_length != -1 ?
 372                        parser->content_length : 0);
 373  
 374      ESP_LOGD(TAG, LOG_FMT("bytes read     = %d"),  parser->nread);
 375      ESP_LOGD(TAG, LOG_FMT("content length = %zu"), r->content_len);
 376  
 377      /* Handle upgrade requests - only WebSocket is supported for now */
 378      if (parser->upgrade) {
 379  #ifdef CONFIG_HTTPD_WS_SUPPORT
 380          ESP_LOGD(TAG, LOG_FMT("Got an upgrade request"));
 381  
 382          /* If there's no "Upgrade" header field, then it's not WebSocket. */
 383          char ws_upgrade_hdr_val[] = "websocket";
 384          if (httpd_req_get_hdr_value_str(r, "Upgrade", ws_upgrade_hdr_val, sizeof(ws_upgrade_hdr_val)) != ESP_OK) {
 385              ESP_LOGW(TAG, LOG_FMT("Upgrade header does not match the length of \"websocket\""));
 386              parser_data->error = HTTPD_400_BAD_REQUEST;
 387              parser_data->status = PARSING_FAILED;
 388              return ESP_FAIL;
 389          }
 390  
 391          /* If "Upgrade" field's key is not "websocket", then we should also forget about it. */
 392          if (strcasecmp("websocket", ws_upgrade_hdr_val) != 0) {
 393              ESP_LOGW(TAG, LOG_FMT("Upgrade header found but it's %s"), ws_upgrade_hdr_val);
 394              parser_data->error = HTTPD_400_BAD_REQUEST;
 395              parser_data->status = PARSING_FAILED;
 396              return ESP_FAIL;
 397          }
 398  
 399          /* Now set handshake flag to true */
 400          ra->ws_handshake_detect = true;
 401  #else
 402          ESP_LOGD(TAG, LOG_FMT("WS functions has been disabled, Upgrade request is not supported."));
 403          parser_data->error = HTTPD_400_BAD_REQUEST;
 404          parser_data->status = PARSING_FAILED;
 405          return ESP_FAIL;
 406  #endif
 407      }
 408  
 409      parser_data->status = PARSING_BODY;
 410      ra->remaining_len = r->content_len;
 411      return ESP_OK;
 412  }
 413  
 414  /* Last http_parser callback if body present in HTTP request.
 415   * Will be invoked ONLY once every packet
 416   */
 417  static esp_err_t cb_on_body(http_parser *parser, const char *at, size_t length)
 418  {
 419      parser_data_t *parser_data = (parser_data_t *) parser->data;
 420  
 421      /* Check previous status */
 422      if (parser_data->status != PARSING_BODY) {
 423          ESP_LOGE(TAG, LOG_FMT("unexpected state transition"));
 424          parser_data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
 425          parser_data->status = PARSING_FAILED;
 426          return ESP_FAIL;
 427      }
 428  
 429      /* Pause parsing so that if part of another packet
 430       * is in queue then it doesn't get parsed, which
 431       * may reset the parser state and cause current
 432       * request packet to be lost */
 433      if (pause_parsing(parser, at) != ESP_OK) {
 434          parser_data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
 435          parser_data->status = PARSING_FAILED;
 436          return ESP_FAIL;
 437      }
 438  
 439      parser_data->last.at     = 0;
 440      parser_data->last.length = 0;
 441      parser_data->status      = PARSING_COMPLETE;
 442      ESP_LOGD(TAG, LOG_FMT("body begins"));
 443      return ESP_OK;
 444  }
 445  
 446  /* Last http_parser callback if body absent in HTTP request.
 447   * Will be invoked ONLY once every packet
 448   */
 449  static esp_err_t cb_no_body(http_parser *parser)
 450  {
 451      parser_data_t *parser_data = (parser_data_t *) parser->data;
 452  
 453      /* Check previous status */
 454      if (parser_data->status == PARSING_URL) {
 455          ESP_LOGD(TAG, LOG_FMT("no headers"));
 456          if (verify_url(parser) != ESP_OK) {
 457              /* verify_url would already have set the
 458               * error field of parser data, so only setting
 459               * status to failed */
 460              parser_data->status = PARSING_FAILED;
 461              return ESP_FAIL;
 462          }
 463      } else if (parser_data->status != PARSING_BODY) {
 464          ESP_LOGE(TAG, LOG_FMT("unexpected state transition"));
 465          parser_data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
 466          parser_data->status = PARSING_FAILED;
 467          return ESP_FAIL;
 468      }
 469  
 470      /* Pause parsing so that if part of another packet
 471       * is in queue then it doesn't get parsed, which
 472       * may reset the parser state and cause current
 473       * request packet to be lost */
 474      if (pause_parsing(parser, parser_data->last.at) != ESP_OK) {
 475          parser_data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
 476          parser_data->status = PARSING_FAILED;
 477          return ESP_FAIL;
 478      }
 479  
 480      parser_data->last.at     = 0;
 481      parser_data->last.length = 0;
 482      parser_data->status      = PARSING_COMPLETE;
 483      ESP_LOGD(TAG, LOG_FMT("message complete"));
 484      return ESP_OK;
 485  }
 486  
 487  static int read_block(httpd_req_t *req, size_t offset, size_t length)
 488  {
 489      struct httpd_req_aux *raux  = req->aux;
 490  
 491      /* Limits the read to scratch buffer size */
 492      ssize_t buf_len = MIN(length, (sizeof(raux->scratch) - offset));
 493      if (buf_len <= 0) {
 494          return 0;
 495      }
 496  
 497      /* Receive data into buffer. If data is pending (from unrecv) then return
 498       * immediately after receiving pending data, as pending data may just complete
 499       * this request packet. */
 500      int nbytes = httpd_recv_with_opt(req, raux->scratch + offset, buf_len, true);
 501      if (nbytes < 0) {
 502          ESP_LOGD(TAG, LOG_FMT("error in httpd_recv"));
 503          /* If timeout occurred allow the
 504           * situation to be handled */
 505          if (nbytes == HTTPD_SOCK_ERR_TIMEOUT) {
 506              /* Invoke error handler which may return ESP_OK
 507               * to signal for retrying call to recv(), else it may
 508               * return ESP_FAIL to signal for closure of socket */
 509              return (httpd_req_handle_err(req, HTTPD_408_REQ_TIMEOUT) == ESP_OK) ?
 510                      HTTPD_SOCK_ERR_TIMEOUT : HTTPD_SOCK_ERR_FAIL;
 511          }
 512          /* Some socket error occurred. Return failure
 513           * to force closure of underlying socket.
 514           * Error message is not sent as socket may not
 515           * be valid anymore */
 516          return HTTPD_SOCK_ERR_FAIL;
 517      } else if (nbytes == 0) {
 518          ESP_LOGD(TAG, LOG_FMT("connection closed"));
 519          /* Connection closed by client so no
 520           * need to send error response */
 521          return HTTPD_SOCK_ERR_FAIL;
 522      }
 523  
 524      ESP_LOGD(TAG, LOG_FMT("received HTTP request block size = %d"), nbytes);
 525      return nbytes;
 526  }
 527  
 528  static int parse_block(http_parser *parser, size_t offset, size_t length)
 529  {
 530      parser_data_t        *data  = (parser_data_t *)(parser->data);
 531      httpd_req_t          *req   = data->req;
 532      struct httpd_req_aux *raux  = req->aux;
 533      size_t nparsed = 0;
 534  
 535      if (!length) {
 536          /* Parsing is still happening but nothing to
 537           * parse means no more space left on buffer,
 538           * therefore it can be inferred that the
 539           * request URI/header must be too long */
 540          ESP_LOGW(TAG, LOG_FMT("request URI/header too long"));
 541          switch (data->status) {
 542              case PARSING_URL:
 543                  data->error = HTTPD_414_URI_TOO_LONG;
 544                  break;
 545              case PARSING_HDR_FIELD:
 546              case PARSING_HDR_VALUE:
 547                  data->error = HTTPD_431_REQ_HDR_FIELDS_TOO_LARGE;
 548                  break;
 549              default:
 550                  ESP_LOGE(TAG, LOG_FMT("unexpected state"));
 551                  data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
 552                  break;
 553          }
 554          data->status = PARSING_FAILED;
 555          return -1;
 556      }
 557  
 558      /* Un-pause the parsing if paused */
 559      if (data->paused) {
 560          nparsed = continue_parsing(parser, length);
 561          length -= nparsed;
 562          offset += nparsed;
 563          if (!length) {
 564              return nparsed;
 565          }
 566      }
 567  
 568      /* Execute http_parser */
 569      nparsed = http_parser_execute(parser, &data->settings,
 570                                    raux->scratch + offset, length);
 571  
 572      /* Check state */
 573      if (data->status == PARSING_FAILED) {
 574          /* It is expected that the error field of
 575           * parser data should have been set by now */
 576          ESP_LOGW(TAG, LOG_FMT("parsing failed"));
 577          return -1;
 578      } else if (data->paused) {
 579          /* Update the value of pre_parsed which was set when
 580           * pause_parsing() was called. (length - nparsed) is
 581           * the length of the data that will need to be parsed
 582           * again later and hence must be deducted from the
 583           * pre_parsed length */
 584          data->pre_parsed -= (length - nparsed);
 585          return 0;
 586      } else if (nparsed != length) {
 587          /* http_parser error */
 588          data->error  = HTTPD_400_BAD_REQUEST;
 589          data->status = PARSING_FAILED;
 590          ESP_LOGW(TAG, LOG_FMT("incomplete (%d/%d) with parser error = %d"),
 591                   nparsed, length, parser->http_errno);
 592          return -1;
 593      }
 594  
 595      /* Return with the total length of the request packet
 596       * that has been parsed till now */
 597      ESP_LOGD(TAG, LOG_FMT("parsed block size = %d"), offset + nparsed);
 598      return offset + nparsed;
 599  }
 600  
 601  static void parse_init(httpd_req_t *r, http_parser *parser, parser_data_t *data)
 602  {
 603      /* Initialize parser data */
 604      memset(data, 0, sizeof(parser_data_t));
 605      data->req = r;
 606  
 607      /* Initialize parser */
 608      http_parser_init(parser, HTTP_REQUEST);
 609      parser->data = (void *)data;
 610  
 611      /* Initialize parser settings */
 612      http_parser_settings_init(&data->settings);
 613  
 614      /* Set parser callbacks */
 615      data->settings.on_url              = cb_url;
 616      data->settings.on_header_field     = cb_header_field;
 617      data->settings.on_header_value     = cb_header_value;
 618      data->settings.on_headers_complete = cb_headers_complete;
 619      data->settings.on_body             = cb_on_body;
 620      data->settings.on_message_complete = cb_no_body;
 621  }
 622  
 623  /* Function that receives TCP data and runs parser on it
 624   */
 625  static esp_err_t httpd_parse_req(struct httpd_data *hd)
 626  {
 627      httpd_req_t *r = &hd->hd_req;
 628      int blk_len,  offset;
 629      http_parser   parser;
 630      parser_data_t parser_data;
 631  
 632      /* Initialize parser */
 633      parse_init(r, &parser, &parser_data);
 634  
 635      /* Set offset to start of scratch buffer */
 636      offset = 0;
 637      do {
 638          /* Read block into scratch buffer */
 639          if ((blk_len = read_block(r, offset, PARSER_BLOCK_SIZE)) < 0) {
 640              if (blk_len == HTTPD_SOCK_ERR_TIMEOUT) {
 641                  /* Retry read in case of non-fatal timeout error.
 642                   * read_block() ensures that the timeout error is
 643                   * handled properly so that this doesn't get stuck
 644                   * in an infinite loop */
 645                  continue;
 646              }
 647              /* If not HTTPD_SOCK_ERR_TIMEOUT, returned error must
 648               * be HTTPD_SOCK_ERR_FAIL which means we need to return
 649               * failure and thereby close the underlying socket */
 650              return ESP_FAIL;
 651          }
 652  
 653          /* This is used by the callbacks to track
 654           * data usage of the buffer */
 655          parser_data.raw_datalen = blk_len + offset;
 656  
 657          /* Parse data block from buffer */
 658          if ((offset = parse_block(&parser, offset, blk_len)) < 0) {
 659              /* HTTP error occurred.
 660               * Send error code as response status and
 661               * invoke error handler */
 662              return httpd_req_handle_err(r, parser_data.error);
 663          }
 664      } while (parser_data.status != PARSING_COMPLETE);
 665  
 666      ESP_LOGD(TAG, LOG_FMT("parsing complete"));
 667      return httpd_uri(hd);
 668  }
 669  
 670  static void init_req(httpd_req_t *r, httpd_config_t *config)
 671  {
 672      r->handle = 0;
 673      r->method = 0;
 674      memset((char*)r->uri, 0, sizeof(r->uri));
 675      r->content_len = 0;
 676      r->aux = 0;
 677      r->user_ctx = 0;
 678      r->sess_ctx = 0;
 679      r->free_ctx = 0;
 680      r->ignore_sess_ctx_changes = 0;
 681  }
 682  
 683  static void init_req_aux(struct httpd_req_aux *ra, httpd_config_t *config)
 684  {
 685      ra->sd = 0;
 686      memset(ra->scratch, 0, sizeof(ra->scratch));
 687      ra->remaining_len = 0;
 688      ra->status = 0;
 689      ra->content_type = 0;
 690      ra->first_chunk_sent = 0;
 691      ra->req_hdrs_count = 0;
 692      ra->resp_hdrs_count = 0;
 693  #if CONFIG_HTTPD_WS_SUPPORT
 694      ra->ws_handshake_detect = false;
 695  #endif
 696      memset(ra->resp_hdrs, 0, config->max_resp_headers * sizeof(struct resp_hdr));
 697  }
 698  
 699  static void httpd_req_cleanup(httpd_req_t *r)
 700  {
 701      struct httpd_req_aux *ra = r->aux;
 702  
 703      /* Check if the context has changed and needs to be cleared */
 704      if ((r->ignore_sess_ctx_changes == false) && (ra->sd->ctx != r->sess_ctx)) {
 705          httpd_sess_free_ctx(ra->sd->ctx, ra->sd->free_ctx);
 706      }
 707  
 708  #if CONFIG_HTTPD_WS_SUPPORT
 709      /* Close the socket when a WebSocket Close request is received */
 710      if (ra->sd->ws_close) {
 711          ESP_LOGD(TAG, LOG_FMT("Try closing WS connection at FD: %d"), ra->sd->fd);
 712          httpd_sess_trigger_close(r->handle, ra->sd->fd);
 713      }
 714  #endif
 715  
 716      /* Retrieve session info from the request into the socket database. */
 717      ra->sd->ctx = r->sess_ctx;
 718      ra->sd->free_ctx = r->free_ctx;
 719      ra->sd->ignore_sess_ctx_changes = r->ignore_sess_ctx_changes;
 720  
 721      /* Clear out the request and request_aux structures */
 722      ra->sd = NULL;
 723      r->handle = NULL;
 724      r->aux = NULL;
 725  }
 726  
 727  /* Function that processes incoming TCP data and
 728   * updates the http request data httpd_req_t
 729   */
 730  esp_err_t httpd_req_new(struct httpd_data *hd, struct sock_db *sd)
 731  {
 732      httpd_req_t *r = &hd->hd_req;
 733      init_req(r, &hd->config);
 734      init_req_aux(&hd->hd_req_aux, &hd->config);
 735      r->handle = hd;
 736      r->aux = &hd->hd_req_aux;
 737  
 738      /* Associate the request to the socket */
 739      struct httpd_req_aux *ra = r->aux;
 740      ra->sd = sd;
 741  
 742      /* Set defaults */
 743      ra->status = (char *)HTTPD_200;
 744      ra->content_type = (char *)HTTPD_TYPE_TEXT;
 745      ra->first_chunk_sent = false;
 746  
 747      /* Copy session info to the request */
 748      r->sess_ctx = sd->ctx;
 749      r->free_ctx = sd->free_ctx;
 750      r->ignore_sess_ctx_changes = sd->ignore_sess_ctx_changes;
 751  
 752      esp_err_t ret;
 753  
 754  #ifdef CONFIG_HTTPD_WS_SUPPORT
 755      /* Handle WebSocket */
 756      ESP_LOGD(TAG, LOG_FMT("New request, has WS? %s, sd->ws_handler valid? %s, sd->ws_close? %s"),
 757               sd->ws_handshake_done ? "Yes" : "No",
 758               sd->ws_handler != NULL ? "Yes" : "No",
 759               sd->ws_close ? "Yes" : "No");
 760      if (sd->ws_handshake_done && sd->ws_handler != NULL) {
 761          ret = httpd_ws_get_frame_type(r);
 762          ESP_LOGD(TAG, LOG_FMT("New WS request from existing socket, ws_type=%d"), ra->ws_type);
 763  
 764          /*  Stop and return here immediately if it's a CLOSE frame */
 765          if (ra->ws_type == HTTPD_WS_TYPE_CLOSE) {
 766              sd->ws_close = true;
 767              return ret;
 768          }
 769  
 770          if (ra->ws_type == HTTPD_WS_TYPE_PONG) {
 771              /* Pass the PONG frames to the handler as well, as user app might send PINGs */
 772              ESP_LOGD(TAG, LOG_FMT("Received PONG frame"));
 773          }
 774  
 775          /* Call handler if it's a non-control frame (or if handler requests control frames, as well) */
 776          if (ret == ESP_OK &&
 777              (ra->ws_type < HTTPD_WS_TYPE_CLOSE || sd->ws_control_frames)) {
 778              ret = sd->ws_handler(r);
 779          }
 780  
 781          if (ret != ESP_OK) {
 782              httpd_req_cleanup(r);
 783          }
 784          return ret;
 785      }
 786  #endif
 787  
 788      /* Parse request */
 789      ret = httpd_parse_req(hd);
 790      if (ret != ESP_OK) {
 791          httpd_req_cleanup(r);
 792      }
 793      return ret;
 794  }
 795  
 796  /* Function that resets the http request data
 797   */
 798  esp_err_t httpd_req_delete(struct httpd_data *hd)
 799  {
 800      httpd_req_t *r = &hd->hd_req;
 801      struct httpd_req_aux *ra = r->aux;
 802  
 803      /* Finish off reading any pending/leftover data */
 804      while (ra->remaining_len) {
 805          /* Any length small enough not to overload the stack, but large
 806           * enough to finish off the buffers fast */
 807          char dummy[CONFIG_HTTPD_PURGE_BUF_LEN];
 808          int recv_len = MIN(sizeof(dummy), ra->remaining_len);
 809          recv_len = httpd_req_recv(r, dummy, recv_len);
 810          if (recv_len < 0) {
 811              httpd_req_cleanup(r);
 812              return ESP_FAIL;
 813          }
 814  
 815          ESP_LOGD(TAG, LOG_FMT("purging data size : %d bytes"), recv_len);
 816  
 817  #ifdef CONFIG_HTTPD_LOG_PURGE_DATA
 818          /* Enabling this will log discarded binary HTTP content data at
 819           * Debug level. For large content data this may not be desirable
 820           * as it will clutter the log */
 821          ESP_LOGD(TAG, "================= PURGED DATA =================");
 822          ESP_LOG_BUFFER_HEX_LEVEL(TAG, dummy, recv_len, ESP_LOG_DEBUG);
 823          ESP_LOGD(TAG, "===============================================");
 824  #endif
 825      }
 826  
 827      httpd_req_cleanup(r);
 828      return ESP_OK;
 829  }
 830  
 831  /* Validates the request to prevent users from calling APIs, that are to
 832   * be called only inside URI handler, outside the handler context
 833   */
 834  bool httpd_validate_req_ptr(httpd_req_t *r)
 835  {
 836      if (r) {
 837          struct httpd_data *hd = (struct httpd_data *) r->handle;
 838          if (hd) {
 839              /* Check if this function is running in the context of
 840               * the correct httpd server thread */
 841              if (httpd_os_thread_handle() == hd->hd_td.handle) {
 842                  return true;
 843              }
 844          }
 845      }
 846      return false;
 847  }
 848  
 849  /* Helper function to get a URL query tag from a query string of the type param1=val1&param2=val2 */
 850  esp_err_t httpd_query_key_value(const char *qry_str, const char *key, char *val, size_t val_size)
 851  {
 852      if (qry_str == NULL || key == NULL || val == NULL) {
 853          return ESP_ERR_INVALID_ARG;
 854      }
 855  
 856      const char   *qry_ptr = qry_str;
 857      const size_t  buf_len = val_size;
 858  
 859      while (strlen(qry_ptr)) {
 860          /* Search for the '=' character. Else, it would mean
 861           * that the parameter is invalid */
 862          const char *val_ptr = strchr(qry_ptr, '=');
 863          if (!val_ptr) {
 864              break;
 865          }
 866          size_t offset = val_ptr - qry_ptr;
 867  
 868          /* If the key, does not match, continue searching.
 869           * Compare lengths first as key from url is not
 870           * null terminated (has '=' in the end) */
 871          if ((offset != strlen(key)) ||
 872              (strncasecmp(qry_ptr, key, offset))) {
 873              /* Get the name=val string. Multiple name=value pairs
 874               * are separated by '&' */
 875              qry_ptr = strchr(val_ptr, '&');
 876              if (!qry_ptr) {
 877                  break;
 878              }
 879              qry_ptr++;
 880              continue;
 881          }
 882  
 883          /* Locate start of next query */
 884          qry_ptr = strchr(++val_ptr, '&');
 885          /* Or this could be the last query, in which
 886           * case get to the end of query string */
 887          if (!qry_ptr) {
 888              qry_ptr = val_ptr + strlen(val_ptr);
 889          }
 890  
 891          /* Update value length, including one byte for null */
 892          val_size = qry_ptr - val_ptr + 1;
 893  
 894          /* Copy value to the caller's buffer. */
 895          strlcpy(val, val_ptr, MIN(val_size, buf_len));
 896  
 897          /* If buffer length is smaller than needed, return truncation error */
 898          if (buf_len < val_size) {
 899              return ESP_ERR_HTTPD_RESULT_TRUNC;
 900          }
 901          return ESP_OK;
 902      }
 903      ESP_LOGD(TAG, LOG_FMT("key %s not found"), key);
 904      return ESP_ERR_NOT_FOUND;
 905  }
 906  
 907  size_t httpd_req_get_url_query_len(httpd_req_t *r)
 908  {
 909      if (r == NULL) {
 910          return 0;
 911      }
 912  
 913      if (!httpd_valid_req(r)) {
 914          return 0;
 915      }
 916  
 917      struct httpd_req_aux   *ra  = r->aux;
 918      struct http_parser_url *res = &ra->url_parse_res;
 919  
 920      /* Check if query field is present in the URL */
 921      if (res->field_set & (1 << UF_QUERY)) {
 922          return res->field_data[UF_QUERY].len;
 923      }
 924      return 0;
 925  }
 926  
 927  esp_err_t httpd_req_get_url_query_str(httpd_req_t *r, char *buf, size_t buf_len)
 928  {
 929      if (r == NULL || buf == NULL) {
 930          return ESP_ERR_INVALID_ARG;
 931      }
 932  
 933      if (!httpd_valid_req(r)) {
 934          return ESP_ERR_HTTPD_INVALID_REQ;
 935      }
 936  
 937      struct httpd_req_aux   *ra  = r->aux;
 938      struct http_parser_url *res = &ra->url_parse_res;
 939  
 940      /* Check if query field is present in the URL */
 941      if (res->field_set & (1 << UF_QUERY)) {
 942          const char *qry = r->uri + res->field_data[UF_QUERY].off;
 943  
 944          /* Minimum required buffer len for keeping
 945           * null terminated query string */
 946          size_t min_buf_len = res->field_data[UF_QUERY].len + 1;
 947  
 948          strlcpy(buf, qry, MIN(buf_len, min_buf_len));
 949          if (buf_len < min_buf_len) {
 950              return ESP_ERR_HTTPD_RESULT_TRUNC;
 951          }
 952          return ESP_OK;
 953      }
 954      return ESP_ERR_NOT_FOUND;
 955  }
 956  
 957  /* Get the length of the value string of a header request field */
 958  size_t httpd_req_get_hdr_value_len(httpd_req_t *r, const char *field)
 959  {
 960      if (r == NULL || field == NULL) {
 961          return 0;
 962      }
 963  
 964      if (!httpd_valid_req(r)) {
 965          return 0;
 966      }
 967  
 968      struct httpd_req_aux *ra = r->aux;
 969      const char   *hdr_ptr = ra->scratch;         /*!< Request headers are kept in scratch buffer */
 970      unsigned      count   = ra->req_hdrs_count;  /*!< Count set during parsing  */
 971  
 972      while (count--) {
 973          /* Search for the ':' character. Else, it would mean
 974           * that the field is invalid
 975           */
 976          const char *val_ptr = strchr(hdr_ptr, ':');
 977          if (!val_ptr) {
 978              break;
 979          }
 980  
 981          /* If the field, does not match, continue searching.
 982           * Compare lengths first as field from header is not
 983           * null terminated (has ':' in the end).
 984           */
 985          if ((val_ptr - hdr_ptr != strlen(field)) ||
 986              (strncasecmp(hdr_ptr, field, strlen(field)))) {
 987              if (count) {
 988                  /* Jump to end of header field-value string */
 989                  hdr_ptr = 1 + strchr(hdr_ptr, '\0');
 990  
 991                  /* Skip all null characters (with which the line
 992                   * terminators had been overwritten) */
 993                  while (*hdr_ptr == '\0') {
 994                      hdr_ptr++;
 995                  }
 996              }
 997              continue;
 998          }
 999  
1000          /* Skip ':' */
1001          val_ptr++;
1002  
1003          /* Skip preceding space */
1004          while ((*val_ptr != '\0') && (*val_ptr == ' ')) {
1005              val_ptr++;
1006          }
1007          return strlen(val_ptr);
1008      }
1009      return 0;
1010  }
1011  
1012  /* Get the value of a field from the request headers */
1013  esp_err_t httpd_req_get_hdr_value_str(httpd_req_t *r, const char *field, char *val, size_t val_size)
1014  {
1015      if (r == NULL || field == NULL) {
1016          return ESP_ERR_INVALID_ARG;
1017      }
1018  
1019      if (!httpd_valid_req(r)) {
1020          return ESP_ERR_HTTPD_INVALID_REQ;
1021      }
1022  
1023      struct httpd_req_aux *ra = r->aux;
1024      const char   *hdr_ptr = ra->scratch;         /*!< Request headers are kept in scratch buffer */
1025      unsigned     count    = ra->req_hdrs_count;  /*!< Count set during parsing  */
1026      const size_t buf_len  = val_size;
1027  
1028      while (count--) {
1029          /* Search for the ':' character. Else, it would mean
1030           * that the field is invalid
1031           */
1032          const char *val_ptr = strchr(hdr_ptr, ':');
1033          if (!val_ptr) {
1034              break;
1035          }
1036  
1037          /* If the field, does not match, continue searching.
1038           * Compare lengths first as field from header is not
1039           * null terminated (has ':' in the end).
1040           */
1041          if ((val_ptr - hdr_ptr != strlen(field)) ||
1042              (strncasecmp(hdr_ptr, field, strlen(field)))) {
1043              if (count) {
1044                  /* Jump to end of header field-value string */
1045                  hdr_ptr = 1 + strchr(hdr_ptr, '\0');
1046  
1047                  /* Skip all null characters (with which the line
1048                   * terminators had been overwritten) */
1049                  while (*hdr_ptr == '\0') {
1050                      hdr_ptr++;
1051                  }
1052              }
1053              continue;
1054          }
1055  
1056          /* Skip ':' */
1057          val_ptr++;
1058  
1059          /* Skip preceding space */
1060          while ((*val_ptr != '\0') && (*val_ptr == ' ')) {
1061              val_ptr++;
1062          }
1063  
1064          /* Get the NULL terminated value and copy it to the caller's buffer. */
1065          strlcpy(val, val_ptr, buf_len);
1066  
1067          /* Update value length, including one byte for null */
1068          val_size = strlen(val_ptr) + 1;
1069  
1070          /* If buffer length is smaller than needed, return truncation error */
1071          if (buf_len < val_size) {
1072              return ESP_ERR_HTTPD_RESULT_TRUNC;
1073          }
1074          return ESP_OK;
1075      }
1076      return ESP_ERR_NOT_FOUND;
1077  }