/ components / esp_http_server / src / httpd_txrx.c
httpd_txrx.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 <errno.h>
 17  #include <esp_log.h>
 18  #include <esp_err.h>
 19  
 20  #include <esp_http_server.h>
 21  #include "esp_httpd_priv.h"
 22  
 23  static const char *TAG = "httpd_txrx";
 24  
 25  esp_err_t httpd_sess_set_send_override(httpd_handle_t hd, int sockfd, httpd_send_func_t send_func)
 26  {
 27      struct sock_db *sess = httpd_sess_get(hd, sockfd);
 28      if (!sess) {
 29          return ESP_ERR_INVALID_ARG;
 30      }
 31      sess->send_fn = send_func;
 32      return ESP_OK;
 33  }
 34  
 35  esp_err_t httpd_sess_set_recv_override(httpd_handle_t hd, int sockfd, httpd_recv_func_t recv_func)
 36  {
 37      struct sock_db *sess = httpd_sess_get(hd, sockfd);
 38      if (!sess) {
 39          return ESP_ERR_INVALID_ARG;
 40      }
 41      sess->recv_fn = recv_func;
 42      return ESP_OK;
 43  }
 44  
 45  esp_err_t httpd_sess_set_pending_override(httpd_handle_t hd, int sockfd, httpd_pending_func_t pending_func)
 46  {
 47      struct sock_db *sess = httpd_sess_get(hd, sockfd);
 48      if (!sess) {
 49          return ESP_ERR_INVALID_ARG;
 50      }
 51      sess->pending_fn = pending_func;
 52      return ESP_OK;
 53  }
 54  
 55  int httpd_send(httpd_req_t *r, const char *buf, size_t buf_len)
 56  {
 57      if (r == NULL || buf == NULL) {
 58          return HTTPD_SOCK_ERR_INVALID;
 59      }
 60  
 61      if (!httpd_valid_req(r)) {
 62          return HTTPD_SOCK_ERR_INVALID;
 63      }
 64  
 65      struct httpd_req_aux *ra = r->aux;
 66      int ret = ra->sd->send_fn(ra->sd->handle, ra->sd->fd, buf, buf_len, 0);
 67      if (ret < 0) {
 68          ESP_LOGD(TAG, LOG_FMT("error in send_fn"));
 69          return ret;
 70      }
 71      return ret;
 72  }
 73  
 74  static esp_err_t httpd_send_all(httpd_req_t *r, const char *buf, size_t buf_len)
 75  {
 76      struct httpd_req_aux *ra = r->aux;
 77      int ret;
 78  
 79      while (buf_len > 0) {
 80          ret = ra->sd->send_fn(ra->sd->handle, ra->sd->fd, buf, buf_len, 0);
 81          if (ret < 0) {
 82              ESP_LOGD(TAG, LOG_FMT("error in send_fn"));
 83              return ESP_FAIL;
 84          }
 85          ESP_LOGD(TAG, LOG_FMT("sent = %d"), ret);
 86          buf     += ret;
 87          buf_len -= ret;
 88      }
 89      return ESP_OK;
 90  }
 91  
 92  static size_t httpd_recv_pending(httpd_req_t *r, char *buf, size_t buf_len)
 93  {
 94      struct httpd_req_aux *ra = r->aux;
 95      size_t offset = sizeof(ra->sd->pending_data) - ra->sd->pending_len;
 96  
 97      /* buf_len must not be greater than remaining_len */
 98      buf_len = MIN(ra->sd->pending_len, buf_len);
 99      memcpy(buf, ra->sd->pending_data + offset, buf_len);
100  
101      ra->sd->pending_len -= buf_len;
102      return buf_len;
103  }
104  
105  int httpd_recv_with_opt(httpd_req_t *r, char *buf, size_t buf_len, bool halt_after_pending)
106  {
107      ESP_LOGD(TAG, LOG_FMT("requested length = %d"), buf_len);
108  
109      size_t pending_len = 0;
110      struct httpd_req_aux *ra = r->aux;
111  
112      /* First fetch pending data from local buffer */
113      if (ra->sd->pending_len > 0) {
114          ESP_LOGD(TAG, LOG_FMT("pending length = %d"), ra->sd->pending_len);
115          pending_len = httpd_recv_pending(r, buf, buf_len);
116          buf     += pending_len;
117          buf_len -= pending_len;
118  
119          /* If buffer filled then no need to recv.
120           * If asked to halt after receiving pending data then
121           * return with received length */
122          if (!buf_len || halt_after_pending) {
123              return pending_len;
124          }
125      }
126  
127      /* Receive data of remaining length */
128      int ret = ra->sd->recv_fn(ra->sd->handle, ra->sd->fd, buf, buf_len, 0);
129      if (ret < 0) {
130          ESP_LOGD(TAG, LOG_FMT("error in recv_fn"));
131          if ((ret == HTTPD_SOCK_ERR_TIMEOUT) && (pending_len != 0)) {
132              /* If recv() timeout occurred, but pending data is
133               * present, return length of pending data.
134               * This behavior is similar to that of socket recv()
135               * function, which, in case has only partially read the
136               * requested length, due to timeout, returns with read
137               * length, rather than error */
138              return pending_len;
139          }
140          return ret;
141      }
142  
143      ESP_LOGD(TAG, LOG_FMT("received length = %d"), ret + pending_len);
144      return ret + pending_len;
145  }
146  
147  int httpd_recv(httpd_req_t *r, char *buf, size_t buf_len)
148  {
149      return httpd_recv_with_opt(r, buf, buf_len, false);
150  }
151  
152  size_t httpd_unrecv(struct httpd_req *r, const char *buf, size_t buf_len)
153  {
154      struct httpd_req_aux *ra = r->aux;
155      /* Truncate if external buf_len is greater than pending_data buffer size */
156      ra->sd->pending_len = MIN(sizeof(ra->sd->pending_data), buf_len);
157  
158      /* Copy data into internal pending_data buffer with the exact offset
159       * such that it is right aligned inside the buffer */
160      size_t offset = sizeof(ra->sd->pending_data) - ra->sd->pending_len;
161      memcpy(ra->sd->pending_data + offset, buf, ra->sd->pending_len);
162      ESP_LOGD(TAG, LOG_FMT("length = %d"), ra->sd->pending_len);
163      return ra->sd->pending_len;
164  }
165  
166  /**
167   * This API appends an additional header field-value pair in the HTTP response.
168   * But the header isn't sent out until any of the send APIs is executed.
169   */
170  esp_err_t httpd_resp_set_hdr(httpd_req_t *r, const char *field, const char *value)
171  {
172      if (r == NULL || field == NULL || value == NULL) {
173          return ESP_ERR_INVALID_ARG;
174      }
175  
176      if (!httpd_valid_req(r)) {
177          return ESP_ERR_HTTPD_INVALID_REQ;
178      }
179  
180      struct httpd_req_aux *ra = r->aux;
181      struct httpd_data *hd = (struct httpd_data *) r->handle;
182  
183      /* Number of additional headers is limited */
184      if (ra->resp_hdrs_count >= hd->config.max_resp_headers) {
185          return ESP_ERR_HTTPD_RESP_HDR;
186      }
187  
188      /* Assign header field-value pair */
189      ra->resp_hdrs[ra->resp_hdrs_count].field = field;
190      ra->resp_hdrs[ra->resp_hdrs_count].value = value;
191      ra->resp_hdrs_count++;
192  
193      ESP_LOGD(TAG, LOG_FMT("new header = %s: %s"), field, value);
194      return ESP_OK;
195  }
196  
197  /**
198   * This API sets the status of the HTTP response to the value specified.
199   * But the status isn't sent out until any of the send APIs is executed.
200   */
201  esp_err_t httpd_resp_set_status(httpd_req_t *r, const char *status)
202  {
203      if (r == NULL || status == NULL) {
204          return ESP_ERR_INVALID_ARG;
205      }
206  
207      if (!httpd_valid_req(r)) {
208          return ESP_ERR_HTTPD_INVALID_REQ;
209      }
210  
211      struct httpd_req_aux *ra = r->aux;
212      ra->status = (char *)status;
213      return ESP_OK;
214  }
215  
216  /**
217   * This API sets the method/type of the HTTP response to the value specified.
218   * But the method isn't sent out until any of the send APIs is executed.
219   */
220  esp_err_t httpd_resp_set_type(httpd_req_t *r, const char *type)
221  {
222      if (r == NULL || type == NULL) {
223          return ESP_ERR_INVALID_ARG;
224      }
225  
226      if (!httpd_valid_req(r)) {
227          return ESP_ERR_HTTPD_INVALID_REQ;
228      }
229  
230      struct httpd_req_aux *ra = r->aux;
231      ra->content_type = (char *)type;
232      return ESP_OK;
233  }
234  
235  esp_err_t httpd_resp_send(httpd_req_t *r, const char *buf, ssize_t buf_len)
236  {
237      if (r == NULL) {
238          return ESP_ERR_INVALID_ARG;
239      }
240  
241      if (!httpd_valid_req(r)) {
242          return ESP_ERR_HTTPD_INVALID_REQ;
243      }
244  
245      struct httpd_req_aux *ra = r->aux;
246      const char *httpd_hdr_str = "HTTP/1.1 %s\r\nContent-Type: %s\r\nContent-Length: %d\r\n";
247      const char *colon_separator = ": ";
248      const char *cr_lf_seperator = "\r\n";
249  
250      if (buf_len == HTTPD_RESP_USE_STRLEN) {
251          buf_len = strlen(buf);
252      }
253  
254      /* Request headers are no longer available */
255      ra->req_hdrs_count = 0;
256  
257      /* Size of essential headers is limited by scratch buffer size */
258      if (snprintf(ra->scratch, sizeof(ra->scratch), httpd_hdr_str,
259                   ra->status, ra->content_type, buf_len) >= sizeof(ra->scratch)) {
260          return ESP_ERR_HTTPD_RESP_HDR;
261      }
262  
263      /* Sending essential headers */
264      if (httpd_send_all(r, ra->scratch, strlen(ra->scratch)) != ESP_OK) {
265          return ESP_ERR_HTTPD_RESP_SEND;
266      }
267  
268      /* Sending additional headers based on set_header */
269      for (unsigned i = 0; i < ra->resp_hdrs_count; i++) {
270          /* Send header field */
271          if (httpd_send_all(r, ra->resp_hdrs[i].field, strlen(ra->resp_hdrs[i].field)) != ESP_OK) {
272              return ESP_ERR_HTTPD_RESP_SEND;
273          }
274          /* Send ': ' */
275          if (httpd_send_all(r, colon_separator, strlen(colon_separator)) != ESP_OK) {
276              return ESP_ERR_HTTPD_RESP_SEND;
277          }
278          /* Send header value */
279          if (httpd_send_all(r, ra->resp_hdrs[i].value, strlen(ra->resp_hdrs[i].value)) != ESP_OK) {
280              return ESP_ERR_HTTPD_RESP_SEND;
281          }
282          /* Send CR + LF */
283          if (httpd_send_all(r, cr_lf_seperator, strlen(cr_lf_seperator)) != ESP_OK) {
284              return ESP_ERR_HTTPD_RESP_SEND;
285          }
286      }
287  
288      /* End header section */
289      if (httpd_send_all(r, cr_lf_seperator, strlen(cr_lf_seperator)) != ESP_OK) {
290          return ESP_ERR_HTTPD_RESP_SEND;
291      }
292  
293      /* Sending content */
294      if (buf && buf_len) {
295          if (httpd_send_all(r, buf, buf_len) != ESP_OK) {
296              return ESP_ERR_HTTPD_RESP_SEND;
297          }
298      }
299      return ESP_OK;
300  }
301  
302  esp_err_t httpd_resp_send_chunk(httpd_req_t *r, const char *buf, ssize_t buf_len)
303  {
304      if (r == NULL) {
305          return ESP_ERR_INVALID_ARG;
306      }
307  
308      if (!httpd_valid_req(r)) {
309          return ESP_ERR_HTTPD_INVALID_REQ;
310      }
311  
312      if (buf_len == HTTPD_RESP_USE_STRLEN) {
313          buf_len = strlen(buf);
314      }
315  
316      struct httpd_req_aux *ra = r->aux;
317      const char *httpd_chunked_hdr_str = "HTTP/1.1 %s\r\nContent-Type: %s\r\nTransfer-Encoding: chunked\r\n";
318      const char *colon_separator = ": ";
319      const char *cr_lf_seperator = "\r\n";
320  
321      /* Request headers are no longer available */
322      ra->req_hdrs_count = 0;
323  
324      if (!ra->first_chunk_sent) {
325          /* Size of essential headers is limited by scratch buffer size */
326          if (snprintf(ra->scratch, sizeof(ra->scratch), httpd_chunked_hdr_str,
327                       ra->status, ra->content_type) >= sizeof(ra->scratch)) {
328              return ESP_ERR_HTTPD_RESP_HDR;
329          }
330  
331          /* Sending essential headers */
332          if (httpd_send_all(r, ra->scratch, strlen(ra->scratch)) != ESP_OK) {
333              return ESP_ERR_HTTPD_RESP_SEND;
334          }
335  
336          /* Sending additional headers based on set_header */
337          for (unsigned i = 0; i < ra->resp_hdrs_count; i++) {
338              /* Send header field */
339              if (httpd_send_all(r, ra->resp_hdrs[i].field, strlen(ra->resp_hdrs[i].field)) != ESP_OK) {
340                  return ESP_ERR_HTTPD_RESP_SEND;
341              }
342              /* Send ': ' */
343              if (httpd_send_all(r, colon_separator, strlen(colon_separator)) != ESP_OK) {
344                  return ESP_ERR_HTTPD_RESP_SEND;
345              }
346              /* Send header value */
347              if (httpd_send_all(r, ra->resp_hdrs[i].value, strlen(ra->resp_hdrs[i].value)) != ESP_OK) {
348                  return ESP_ERR_HTTPD_RESP_SEND;
349              }
350              /* Send CR + LF */
351              if (httpd_send_all(r, cr_lf_seperator, strlen(cr_lf_seperator)) != ESP_OK) {
352                  return ESP_ERR_HTTPD_RESP_SEND;
353              }
354          }
355  
356          /* End header section */
357          if (httpd_send_all(r, cr_lf_seperator, strlen(cr_lf_seperator)) != ESP_OK) {
358              return ESP_ERR_HTTPD_RESP_SEND;
359          }
360          ra->first_chunk_sent = true;
361      }
362  
363      /* Sending chunked content */
364      char len_str[10];
365      snprintf(len_str, sizeof(len_str), "%x\r\n", buf_len);
366      if (httpd_send_all(r, len_str, strlen(len_str)) != ESP_OK) {
367          return ESP_ERR_HTTPD_RESP_SEND;
368      }
369  
370      if (buf) {
371          if (httpd_send_all(r, buf, (size_t) buf_len) != ESP_OK) {
372              return ESP_ERR_HTTPD_RESP_SEND;
373          }
374      }
375  
376      /* Indicate end of chunk */
377      if (httpd_send_all(r, "\r\n", strlen("\r\n")) != ESP_OK) {
378          return ESP_ERR_HTTPD_RESP_SEND;
379      }
380      return ESP_OK;
381  }
382  
383  esp_err_t httpd_resp_send_err(httpd_req_t *req, httpd_err_code_t error, const char *usr_msg)
384  {
385      esp_err_t ret;
386      const char *msg;
387      const char *status;
388  
389      switch (error) {
390          case HTTPD_501_METHOD_NOT_IMPLEMENTED:
391              status = "501 Method Not Implemented";
392              msg    = "Request method is not supported by server";
393              break;
394          case HTTPD_505_VERSION_NOT_SUPPORTED:
395              status = "505 Version Not Supported";
396              msg    = "HTTP version not supported by server";
397              break;
398          case HTTPD_400_BAD_REQUEST:
399              status = "400 Bad Request";
400              msg    = "Server unable to understand request due to invalid syntax";
401              break;
402          case HTTPD_404_NOT_FOUND:
403              status = "404 Not Found";
404              msg    = "This URI does not exist";
405              break;
406          case HTTPD_405_METHOD_NOT_ALLOWED:
407              status = "405 Method Not Allowed";
408              msg    = "Request method for this URI is not handled by server";
409              break;
410          case HTTPD_408_REQ_TIMEOUT:
411              status = "408 Request Timeout";
412              msg    = "Server closed this connection";
413              break;
414          case HTTPD_414_URI_TOO_LONG:
415              status = "414 URI Too Long";
416              msg    = "URI is too long for server to interpret";
417              break;
418          case HTTPD_411_LENGTH_REQUIRED:
419              status = "411 Length Required";
420              msg    = "Chunked encoding not supported by server";
421              break;
422          case HTTPD_431_REQ_HDR_FIELDS_TOO_LARGE:
423              status = "431 Request Header Fields Too Large";
424              msg    = "Header fields are too long for server to interpret";
425              break;
426          case HTTPD_500_INTERNAL_SERVER_ERROR:
427          default:
428              status = "500 Internal Server Error";
429              msg    = "Server has encountered an unexpected error";
430      }
431  
432      /* If user has provided custom message, override default message */
433      msg = usr_msg ? usr_msg : msg;
434      ESP_LOGW(TAG, LOG_FMT("%s - %s"), status, msg);
435  
436      /* Set error code in HTTP response */
437      httpd_resp_set_status(req, status);
438      httpd_resp_set_type(req, HTTPD_TYPE_TEXT);
439  
440  #ifdef CONFIG_HTTPD_ERR_RESP_NO_DELAY
441      /* Use TCP_NODELAY option to force socket to send data in buffer
442       * This ensures that the error message is sent before the socket
443       * is closed */
444      struct httpd_req_aux *ra = req->aux;
445      int nodelay = 1;
446      if (setsockopt(ra->sd->fd, IPPROTO_TCP, TCP_NODELAY, &nodelay, sizeof(nodelay)) < 0) {
447          /* If failed to turn on TCP_NODELAY, throw warning and continue */
448          ESP_LOGW(TAG, LOG_FMT("error calling setsockopt : %d"), errno);
449          nodelay = 0;
450      }
451  #endif
452  
453      /* Send HTTP error message */
454      ret = httpd_resp_send(req, msg, HTTPD_RESP_USE_STRLEN);
455  
456  #ifdef CONFIG_HTTPD_ERR_RESP_NO_DELAY
457      /* If TCP_NODELAY was set successfully above, time to disable it */
458      if (nodelay == 1) {
459          nodelay = 0;
460          if (setsockopt(ra->sd->fd, IPPROTO_TCP, TCP_NODELAY, &nodelay, sizeof(nodelay)) < 0) {
461              /* If failed to turn off TCP_NODELAY, throw error and
462               * return failure to signal for socket closure */
463              ESP_LOGE(TAG, LOG_FMT("error calling setsockopt : %d"), errno);
464              return ESP_ERR_INVALID_STATE;
465          }
466      }
467  #endif
468  
469      return ret;
470  }
471  
472  esp_err_t httpd_register_err_handler(httpd_handle_t handle,
473                                       httpd_err_code_t error,
474                                       httpd_err_handler_func_t err_handler_fn)
475  {
476      if (handle == NULL || error >= HTTPD_ERR_CODE_MAX) {
477          return ESP_ERR_INVALID_ARG;
478      }
479  
480      struct httpd_data *hd = (struct httpd_data *) handle;
481      hd->err_handler_fns[error] = err_handler_fn;
482      return ESP_OK;
483  }
484  
485  esp_err_t httpd_req_handle_err(httpd_req_t *req, httpd_err_code_t error)
486  {
487      struct httpd_data *hd = (struct httpd_data *) req->handle;
488      esp_err_t ret;
489  
490      /* Invoke custom error handler if configured */
491      if (hd->err_handler_fns[error]) {
492          ret = hd->err_handler_fns[error](req, error);
493  
494          /* If error code is 500, force return failure
495           * irrespective of the handler's return value */
496          ret = (error == HTTPD_500_INTERNAL_SERVER_ERROR ? ESP_FAIL : ret);
497      } else {
498          /* If no handler is registered for this error default
499           * behavior is to send the HTTP error response and
500           * return failure for closure of underlying socket */
501          httpd_resp_send_err(req, error, NULL);
502          ret = ESP_FAIL;
503      }
504      return ret;
505  }
506  
507  int httpd_req_recv(httpd_req_t *r, char *buf, size_t buf_len)
508  {
509      if (r == NULL || buf == NULL) {
510          return HTTPD_SOCK_ERR_INVALID;
511      }
512  
513      if (!httpd_valid_req(r)) {
514          ESP_LOGW(TAG, LOG_FMT("invalid request"));
515          return HTTPD_SOCK_ERR_INVALID;
516      }
517  
518      struct httpd_req_aux *ra = r->aux;
519      ESP_LOGD(TAG, LOG_FMT("remaining length = %d"), ra->remaining_len);
520  
521      if (buf_len > ra->remaining_len) {
522          buf_len = ra->remaining_len;
523      }
524      if (buf_len == 0) {
525          return buf_len;
526      }
527  
528      int ret = httpd_recv(r, buf, buf_len);
529      if (ret < 0) {
530          ESP_LOGD(TAG, LOG_FMT("error in httpd_recv"));
531          return ret;
532      }
533      ra->remaining_len -= ret;
534      ESP_LOGD(TAG, LOG_FMT("received length = %d"), ret);
535      return ret;
536  }
537  
538  int httpd_req_to_sockfd(httpd_req_t *r)
539  {
540      if (r == NULL) {
541          return -1;
542      }
543  
544      if (!httpd_valid_req(r)) {
545          ESP_LOGW(TAG, LOG_FMT("invalid request"));
546          return -1;
547      }
548  
549      struct httpd_req_aux *ra = r->aux;
550      return ra->sd->fd;
551  }
552  
553  static int httpd_sock_err(const char *ctx, int sockfd)
554  {
555      int errval;
556      ESP_LOGW(TAG, LOG_FMT("error in %s : %d"), ctx, errno);
557  
558      switch(errno) {
559      case EAGAIN:
560      case EINTR:
561          errval = HTTPD_SOCK_ERR_TIMEOUT;
562          break;
563      case EINVAL:
564      case EBADF:
565      case EFAULT:
566      case ENOTSOCK:
567          errval = HTTPD_SOCK_ERR_INVALID;
568          break;
569      default:
570          errval = HTTPD_SOCK_ERR_FAIL;
571      }
572      return errval;
573  }
574  
575  int httpd_default_send(httpd_handle_t hd, int sockfd, const char *buf, size_t buf_len, int flags)
576  {
577      (void)hd;
578      if (buf == NULL) {
579          return HTTPD_SOCK_ERR_INVALID;
580      }
581  
582      int ret = send(sockfd, buf, buf_len, flags);
583      if (ret < 0) {
584          return httpd_sock_err("send", sockfd);
585      }
586      return ret;
587  }
588  
589  int httpd_default_recv(httpd_handle_t hd, int sockfd, char *buf, size_t buf_len, int flags)
590  {
591      (void)hd;
592      if (buf == NULL) {
593          return HTTPD_SOCK_ERR_INVALID;
594      }
595  
596      int ret = recv(sockfd, buf, buf_len, flags);
597      if (ret < 0) {
598          return httpd_sock_err("recv", sockfd);
599      }
600      return ret;
601  }
602  
603  int httpd_socket_send(httpd_handle_t hd, int sockfd, const char *buf, size_t buf_len, int flags)
604  {
605      struct sock_db *sess = httpd_sess_get(hd, sockfd);
606      if (!sess) {
607          return ESP_ERR_INVALID_ARG;
608      }
609      if (!sess->send_fn) {
610          return ESP_ERR_INVALID_STATE;
611      }
612      return sess->send_fn(hd, sockfd, buf, buf_len, flags);
613  }
614  
615  int httpd_socket_recv(httpd_handle_t hd, int sockfd, char *buf, size_t buf_len, int flags)
616  {
617      struct sock_db *sess = httpd_sess_get(hd, sockfd);
618      if (!sess) {
619          return ESP_ERR_INVALID_ARG;
620      }
621      if (!sess->recv_fn) {
622          return ESP_ERR_INVALID_STATE;
623      }
624      return sess->recv_fn(hd, sockfd, buf, buf_len, flags);
625  }