From ae71e1ddb961f6151756bcfe390f0f59db7b9c45 Mon Sep 17 00:00:00 2001 From: Harshit Malpani Date: Mon, 27 Nov 2023 14:29:37 +0530 Subject: [PATCH] fix(esp_http_server): Add support for custom HTTP status codes Closes https://github.com/espressif/esp-idf/issues/12399 --- .../esp_http_server/include/esp_http_server.h | 24 ++++++++++++ components/esp_http_server/src/httpd_txrx.c | 39 +++++++++++++++++++ 2 files changed, 63 insertions(+) diff --git a/components/esp_http_server/include/esp_http_server.h b/components/esp_http_server/include/esp_http_server.h index 30fee5da81..6b0e789bd4 100644 --- a/components/esp_http_server/include/esp_http_server.h +++ b/components/esp_http_server/include/esp_http_server.h @@ -1293,6 +1293,30 @@ esp_err_t httpd_resp_set_hdr(httpd_req_t *r, const char *field, const char *valu */ esp_err_t httpd_resp_send_err(httpd_req_t *req, httpd_err_code_t error, const char *msg); +/** + * @brief For sending out custom error code in response to HTTP request. + * + * @note + * - This API is supposed to be called only from the context of + * a URI handler where httpd_req_t* request pointer is valid. + * - Once this API is called, all request headers are purged, so + * request headers need be copied into separate buffers if + * they are required later. + * - If you wish to send additional data in the body of the + * response, please use the lower-level functions directly. + * + * @param[in] req Pointer to the HTTP request for which the response needs to be sent + * @param[in] status Error status to send + * @param[in] msg Error message string + * + * @return + * - ESP_OK : On successfully sending the response packet + * - ESP_ERR_INVALID_ARG : Null arguments + * - ESP_ERR_HTTPD_RESP_SEND : Error in raw send + * - ESP_ERR_HTTPD_INVALID_REQ : Invalid request pointer + */ +esp_err_t httpd_resp_send_custom_err(httpd_req_t *req, const char *status, const char *msg); + /** * @brief Helper function for HTTP 404 * diff --git a/components/esp_http_server/src/httpd_txrx.c b/components/esp_http_server/src/httpd_txrx.c index a3c24a10f6..3630bb2833 100644 --- a/components/esp_http_server/src/httpd_txrx.c +++ b/components/esp_http_server/src/httpd_txrx.c @@ -483,6 +483,45 @@ esp_err_t httpd_resp_send_err(httpd_req_t *req, httpd_err_code_t error, const ch return ret; } +esp_err_t httpd_resp_send_custom_err(httpd_req_t *req, const char *status, const char *msg) +{ + ESP_LOGW(TAG, LOG_FMT("%s - %s"), status, msg); + + /* Set error code in HTTP response */ + httpd_resp_set_status(req, status); + httpd_resp_set_type(req, HTTPD_TYPE_TEXT); + +#ifdef CONFIG_HTTPD_ERR_RESP_NO_DELAY + /* Use TCP_NODELAY option to force socket to send data in buffer + * This ensures that the error message is sent before the socket + * is closed */ + struct httpd_req_aux *ra = req->aux; + int nodelay = 1; + if (setsockopt(ra->sd->fd, IPPROTO_TCP, TCP_NODELAY, &nodelay, sizeof(nodelay)) < 0) { + /* If failed to turn on TCP_NODELAY, throw warning and continue */ + ESP_LOGW(TAG, LOG_FMT("error calling setsockopt : %d"), errno); + nodelay = 0; + } +#endif + + /* Send HTTP error message */ + esp_err_t ret = httpd_resp_send(req, msg, HTTPD_RESP_USE_STRLEN); + +#ifdef CONFIG_HTTPD_ERR_RESP_NO_DELAY + /* If TCP_NODELAY was set successfully above, time to disable it */ + if (nodelay == 1) { + nodelay = 0; + if (setsockopt(ra->sd->fd, IPPROTO_TCP, TCP_NODELAY, &nodelay, sizeof(nodelay)) < 0) { + /* If failed to turn off TCP_NODELAY, throw error and + * return failure to signal for socket closure */ + ESP_LOGE(TAG, LOG_FMT("error calling setsockopt : %d"), errno); + return ESP_ERR_INVALID_STATE; + } + } +#endif + return ret; +} + esp_err_t httpd_register_err_handler(httpd_handle_t handle, httpd_err_code_t error, httpd_err_handler_func_t err_handler_fn)