mirror of
https://github.com/espressif/esp-idf.git
synced 2025-08-02 20:24:32 +02:00
Merge branch 'feature/http_server_err_handling' into 'master'
http_server : Add feature for invoking user configurable handlers during server errors See merge request idf/esp-idf!4229
This commit is contained in:
@@ -13,4 +13,11 @@ menu "HTTP Server"
|
|||||||
help
|
help
|
||||||
This sets the maximum supported size of HTTP request URI to be processed by the server
|
This sets the maximum supported size of HTTP request URI to be processed by the server
|
||||||
|
|
||||||
|
config HTTPD_ERR_RESP_NO_DELAY
|
||||||
|
bool "Use TCP_NODELAY socket option when sending HTTP error responses"
|
||||||
|
default y
|
||||||
|
help
|
||||||
|
Using TCP_NODEALY socket option ensures that HTTP error response reaches the client before the
|
||||||
|
underlying socket is closed. Please note that turning this off may cause multiple test failures
|
||||||
|
|
||||||
endmenu
|
endmenu
|
||||||
|
@@ -471,6 +471,122 @@ esp_err_t httpd_unregister_uri(httpd_handle_t handle, const char* uri);
|
|||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
/* ************** Group: HTTP Error ************** */
|
||||||
|
/** @name HTTP Error
|
||||||
|
* Prototype for HTTP errors and error handling functions
|
||||||
|
* @{
|
||||||
|
*/
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Error codes sent as HTTP response in case of errors
|
||||||
|
* encountered during processing of an HTTP request
|
||||||
|
*/
|
||||||
|
typedef enum {
|
||||||
|
/* For any unexpected errors during parsing, like unexpected
|
||||||
|
* state transitions, or unhandled errors.
|
||||||
|
*/
|
||||||
|
HTTPD_500_INTERNAL_SERVER_ERROR = 0,
|
||||||
|
|
||||||
|
/* For methods not supported by http_parser. Presently
|
||||||
|
* http_parser halts parsing when such methods are
|
||||||
|
* encountered and so the server responds with 400 Bad
|
||||||
|
* Request error instead.
|
||||||
|
*/
|
||||||
|
HTTPD_501_METHOD_NOT_IMPLEMENTED,
|
||||||
|
|
||||||
|
/* When HTTP version is not 1.1 */
|
||||||
|
HTTPD_505_VERSION_NOT_SUPPORTED,
|
||||||
|
|
||||||
|
/* Returned when http_parser halts parsing due to incorrect
|
||||||
|
* syntax of request, unsupported method in request URI or
|
||||||
|
* due to chunked encoding / upgrade field present in headers
|
||||||
|
*/
|
||||||
|
HTTPD_400_BAD_REQUEST,
|
||||||
|
|
||||||
|
/* When requested URI is not found */
|
||||||
|
HTTPD_404_NOT_FOUND,
|
||||||
|
|
||||||
|
/* When URI found, but method has no handler registered */
|
||||||
|
HTTPD_405_METHOD_NOT_ALLOWED,
|
||||||
|
|
||||||
|
/* Intended for recv timeout. Presently it's being sent
|
||||||
|
* for other recv errors as well. Client should expect the
|
||||||
|
* server to immediately close the connection after
|
||||||
|
* responding with this.
|
||||||
|
*/
|
||||||
|
HTTPD_408_REQ_TIMEOUT,
|
||||||
|
|
||||||
|
/* Intended for responding to chunked encoding, which is
|
||||||
|
* not supported currently. Though unhandled http_parser
|
||||||
|
* callback for chunked request returns "400 Bad Request"
|
||||||
|
*/
|
||||||
|
HTTPD_411_LENGTH_REQUIRED,
|
||||||
|
|
||||||
|
/* URI length greater than CONFIG_HTTPD_MAX_URI_LEN */
|
||||||
|
HTTPD_414_URI_TOO_LONG,
|
||||||
|
|
||||||
|
/* Headers section larger than CONFIG_HTTPD_MAX_REQ_HDR_LEN */
|
||||||
|
HTTPD_431_REQ_HDR_FIELDS_TOO_LARGE,
|
||||||
|
|
||||||
|
/* Used internally for retrieving the total count of errors */
|
||||||
|
HTTPD_ERR_CODE_MAX
|
||||||
|
} httpd_err_code_t;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function prototype for HTTP error handling.
|
||||||
|
*
|
||||||
|
* This function is executed upon HTTP errors generated during
|
||||||
|
* internal processing of an HTTP request. This is used to override
|
||||||
|
* the default behavior on error, which is to send HTTP error response
|
||||||
|
* and close the underlying socket.
|
||||||
|
*
|
||||||
|
* @note
|
||||||
|
* - If implemented, the server will not automatically send out HTTP
|
||||||
|
* error response codes, therefore, httpd_resp_send_err() must be
|
||||||
|
* invoked inside this function if user wishes to generate HTTP
|
||||||
|
* error responses.
|
||||||
|
* - When invoked, the validity of `uri`, `method`, `content_len`
|
||||||
|
* and `user_ctx` fields of the httpd_req_t parameter is not
|
||||||
|
* guaranteed as the HTTP request may be partially received/parsed.
|
||||||
|
* - The function must return ESP_OK if underlying socket needs to
|
||||||
|
* be kept open. Any other value will ensure that the socket is
|
||||||
|
* closed. The return value is ignored when error is of type
|
||||||
|
* `HTTPD_500_INTERNAL_SERVER_ERROR` and the socket closed anyway.
|
||||||
|
*
|
||||||
|
* @param[in] req HTTP request for which the error needs to be handled
|
||||||
|
* @param[in] error Error type
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK : error handled successful
|
||||||
|
* - ESP_FAIL : failure indicates that the underlying socket needs to be closed
|
||||||
|
*/
|
||||||
|
typedef esp_err_t (*httpd_err_handler_func_t)(httpd_req_t *req,
|
||||||
|
httpd_err_code_t error);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief Function for registering HTTP error handlers
|
||||||
|
*
|
||||||
|
* This function maps a handler function to any supported error code
|
||||||
|
* given by `httpd_err_code_t`. See prototype `httpd_err_handler_func_t`
|
||||||
|
* above for details.
|
||||||
|
*
|
||||||
|
* @param[in] handle HTTP server handle
|
||||||
|
* @param[in] error Error type
|
||||||
|
* @param[in] handler_fn User implemented handler function
|
||||||
|
* (Pass NULL to unset any previously set handler)
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK : handler registered successfully
|
||||||
|
* - ESP_ERR_INVALID_ARG : invalid error code or server handle
|
||||||
|
*/
|
||||||
|
esp_err_t httpd_register_err_handler(httpd_handle_t handle,
|
||||||
|
httpd_err_code_t error,
|
||||||
|
httpd_err_handler_func_t handler_fn);
|
||||||
|
|
||||||
|
/** End of HTTP Error
|
||||||
|
* @}
|
||||||
|
*/
|
||||||
|
|
||||||
/* ************** Group: TX/RX ************** */
|
/* ************** Group: TX/RX ************** */
|
||||||
/** @name TX / RX
|
/** @name TX / RX
|
||||||
* Prototype for HTTPDs low-level send/recv functions
|
* Prototype for HTTPDs low-level send/recv functions
|
||||||
@@ -901,7 +1017,7 @@ esp_err_t httpd_resp_send_chunk(httpd_req_t *r, const char *buf, ssize_t buf_len
|
|||||||
* - ESP_ERR_HTTPD_RESP_SEND : Error in raw send
|
* - ESP_ERR_HTTPD_RESP_SEND : Error in raw send
|
||||||
* - ESP_ERR_HTTPD_INVALID_REQ : Invalid request
|
* - ESP_ERR_HTTPD_INVALID_REQ : Invalid request
|
||||||
*/
|
*/
|
||||||
inline esp_err_t httpd_resp_sendstr(httpd_req_t *r, const char *str) {
|
static inline esp_err_t httpd_resp_sendstr(httpd_req_t *r, const char *str) {
|
||||||
return httpd_resp_send(r, str, (str == NULL) ? 0 : strlen(str));
|
return httpd_resp_send(r, str, (str == NULL) ? 0 : strlen(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -922,7 +1038,7 @@ inline esp_err_t httpd_resp_sendstr(httpd_req_t *r, const char *str) {
|
|||||||
* - ESP_ERR_HTTPD_RESP_SEND : Error in raw send
|
* - ESP_ERR_HTTPD_RESP_SEND : Error in raw send
|
||||||
* - ESP_ERR_HTTPD_INVALID_REQ : Invalid request
|
* - ESP_ERR_HTTPD_INVALID_REQ : Invalid request
|
||||||
*/
|
*/
|
||||||
inline esp_err_t httpd_resp_sendstr_chunk(httpd_req_t *r, const char *str) {
|
static inline esp_err_t httpd_resp_sendstr_chunk(httpd_req_t *r, const char *str) {
|
||||||
return httpd_resp_send_chunk(r, str, (str == NULL) ? 0 : strlen(str));
|
return httpd_resp_send_chunk(r, str, (str == NULL) ? 0 : strlen(str));
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1014,6 +1130,30 @@ esp_err_t httpd_resp_set_type(httpd_req_t *r, const char *type);
|
|||||||
*/
|
*/
|
||||||
esp_err_t httpd_resp_set_hdr(httpd_req_t *r, const char *field, const char *value);
|
esp_err_t httpd_resp_set_hdr(httpd_req_t *r, const char *field, const char *value);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief For sending out 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] error Error type to send
|
||||||
|
* @param[in] msg Error message string (pass NULL for default message)
|
||||||
|
*
|
||||||
|
* @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_err(httpd_req_t *req, httpd_err_code_t error, const char *msg);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Helper function for HTTP 404
|
* @brief Helper function for HTTP 404
|
||||||
*
|
*
|
||||||
@@ -1035,7 +1175,9 @@ esp_err_t httpd_resp_set_hdr(httpd_req_t *r, const char *field, const char *valu
|
|||||||
* - ESP_ERR_HTTPD_RESP_SEND : Error in raw send
|
* - ESP_ERR_HTTPD_RESP_SEND : Error in raw send
|
||||||
* - ESP_ERR_HTTPD_INVALID_REQ : Invalid request pointer
|
* - ESP_ERR_HTTPD_INVALID_REQ : Invalid request pointer
|
||||||
*/
|
*/
|
||||||
esp_err_t httpd_resp_send_404(httpd_req_t *r);
|
static inline esp_err_t httpd_resp_send_404(httpd_req_t *r) {
|
||||||
|
return httpd_resp_send_err(r, HTTPD_404_NOT_FOUND, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Helper function for HTTP 408
|
* @brief Helper function for HTTP 408
|
||||||
@@ -1058,7 +1200,9 @@ esp_err_t httpd_resp_send_404(httpd_req_t *r);
|
|||||||
* - ESP_ERR_HTTPD_RESP_SEND : Error in raw send
|
* - ESP_ERR_HTTPD_RESP_SEND : Error in raw send
|
||||||
* - ESP_ERR_HTTPD_INVALID_REQ : Invalid request pointer
|
* - ESP_ERR_HTTPD_INVALID_REQ : Invalid request pointer
|
||||||
*/
|
*/
|
||||||
esp_err_t httpd_resp_send_408(httpd_req_t *r);
|
static inline esp_err_t httpd_resp_send_408(httpd_req_t *r) {
|
||||||
|
return httpd_resp_send_err(r, HTTPD_408_REQ_TIMEOUT, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Helper function for HTTP 500
|
* @brief Helper function for HTTP 500
|
||||||
@@ -1081,7 +1225,9 @@ esp_err_t httpd_resp_send_408(httpd_req_t *r);
|
|||||||
* - ESP_ERR_HTTPD_RESP_SEND : Error in raw send
|
* - ESP_ERR_HTTPD_RESP_SEND : Error in raw send
|
||||||
* - ESP_ERR_HTTPD_INVALID_REQ : Invalid request pointer
|
* - ESP_ERR_HTTPD_INVALID_REQ : Invalid request pointer
|
||||||
*/
|
*/
|
||||||
esp_err_t httpd_resp_send_500(httpd_req_t *r);
|
static inline esp_err_t httpd_resp_send_500(httpd_req_t *r) {
|
||||||
|
return httpd_resp_send_err(r, HTTPD_500_INTERNAL_SERVER_ERROR, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Raw HTTP send
|
* @brief Raw HTTP send
|
||||||
|
@@ -32,7 +32,7 @@ extern "C" {
|
|||||||
|
|
||||||
/* Size of request data block/chunk (not to be confused with chunked encoded data)
|
/* Size of request data block/chunk (not to be confused with chunked encoded data)
|
||||||
* that is received and parsed in one turn of the parsing process. This should not
|
* that is received and parsed in one turn of the parsing process. This should not
|
||||||
* exceed the scratch buffer size and should atleast be 8 bytes */
|
* exceed the scratch buffer size and should at least be 8 bytes */
|
||||||
#define PARSER_BLOCK_SIZE 128
|
#define PARSER_BLOCK_SIZE 128
|
||||||
|
|
||||||
/* Calculate the maximum size needed for the scratch buffer */
|
/* Calculate the maximum size needed for the scratch buffer */
|
||||||
@@ -54,64 +54,6 @@ struct thread_data {
|
|||||||
} status; /*!< State of the thread */
|
} status; /*!< State of the thread */
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief Error codes sent by server in case of errors
|
|
||||||
* encountered during processing of an HTTP request
|
|
||||||
*/
|
|
||||||
typedef enum {
|
|
||||||
/* For any unexpected errors during parsing, like unexpected
|
|
||||||
* state transitions, or unhandled errors.
|
|
||||||
*/
|
|
||||||
HTTPD_500_SERVER_ERROR = 0,
|
|
||||||
|
|
||||||
/* For methods not supported by http_parser. Presently
|
|
||||||
* http_parser halts parsing when such methods are
|
|
||||||
* encountered and so the server responds with 400 Bad
|
|
||||||
* Request error instead.
|
|
||||||
*/
|
|
||||||
HTTPD_501_METHOD_NOT_IMPLEMENTED,
|
|
||||||
|
|
||||||
/* When HTTP version is not 1.1 */
|
|
||||||
HTTPD_505_VERSION_NOT_SUPPORTED,
|
|
||||||
|
|
||||||
/* Returned when http_parser halts parsing due to incorrect
|
|
||||||
* syntax of request, unsupported method in request URI or
|
|
||||||
* due to chunked encoding option present in headers
|
|
||||||
*/
|
|
||||||
HTTPD_400_BAD_REQUEST,
|
|
||||||
|
|
||||||
/* When requested URI is not found */
|
|
||||||
HTTPD_404_NOT_FOUND,
|
|
||||||
|
|
||||||
/* When URI found, but method has no handler registered */
|
|
||||||
HTTPD_405_METHOD_NOT_ALLOWED,
|
|
||||||
|
|
||||||
/* Intended for recv timeout. Presently it's being sent
|
|
||||||
* for other recv errors as well. Client should expect the
|
|
||||||
* server to immediatly close the connection after
|
|
||||||
* responding with this.
|
|
||||||
*/
|
|
||||||
HTTPD_408_REQ_TIMEOUT,
|
|
||||||
|
|
||||||
/* Intended for responding to chunked encoding, which is
|
|
||||||
* not supported currently. Though unhandled http_parser
|
|
||||||
* callback for chunked request returns "400 Bad Request"
|
|
||||||
*/
|
|
||||||
HTTPD_411_LENGTH_REQUIRED,
|
|
||||||
|
|
||||||
/* URI length greater than HTTPD_MAX_URI_LEN */
|
|
||||||
HTTPD_414_URI_TOO_LONG,
|
|
||||||
|
|
||||||
/* Headers section larger thn HTTPD_MAX_REQ_HDR_LEN */
|
|
||||||
HTTPD_431_REQ_HDR_FIELDS_TOO_LARGE,
|
|
||||||
|
|
||||||
/* There is no particular HTTP error code for not supporting
|
|
||||||
* upgrade. For this respond with 200 OK. Client expects status
|
|
||||||
* code 101 if upgrade were supported, so 200 should be fine.
|
|
||||||
*/
|
|
||||||
HTTPD_XXX_UPGRADE_NOT_SUPPORTED
|
|
||||||
} httpd_err_resp_t;
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief A database of all the open sockets in the system.
|
* @brief A database of all the open sockets in the system.
|
||||||
*/
|
*/
|
||||||
@@ -131,7 +73,7 @@ struct sock_db {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Auxilary data structure for use during reception and processing
|
* @brief Auxiliary data structure for use during reception and processing
|
||||||
* of requests and temporarily keeping responses
|
* of requests and temporarily keeping responses
|
||||||
*/
|
*/
|
||||||
struct httpd_req_aux {
|
struct httpd_req_aux {
|
||||||
@@ -151,7 +93,7 @@ struct httpd_req_aux {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Server data for each instance. This is exposed publicaly as
|
* @brief Server data for each instance. This is exposed publicly as
|
||||||
* httpd_handle_t but internal structure/members are kept private.
|
* httpd_handle_t but internal structure/members are kept private.
|
||||||
*/
|
*/
|
||||||
struct httpd_data {
|
struct httpd_data {
|
||||||
@@ -159,11 +101,14 @@ struct httpd_data {
|
|||||||
int listen_fd; /*!< Server listener FD */
|
int listen_fd; /*!< Server listener FD */
|
||||||
int ctrl_fd; /*!< Ctrl message receiver FD */
|
int ctrl_fd; /*!< Ctrl message receiver FD */
|
||||||
int msg_fd; /*!< Ctrl message sender FD */
|
int msg_fd; /*!< Ctrl message sender FD */
|
||||||
struct thread_data hd_td; /*!< Information for the HTTPd thread */
|
struct thread_data hd_td; /*!< Information for the HTTPD thread */
|
||||||
struct sock_db *hd_sd; /*!< The socket database */
|
struct sock_db *hd_sd; /*!< The socket database */
|
||||||
httpd_uri_t **hd_calls; /*!< Registered URI handlers */
|
httpd_uri_t **hd_calls; /*!< Registered URI handlers */
|
||||||
struct httpd_req hd_req; /*!< The current HTTPD request */
|
struct httpd_req hd_req; /*!< The current HTTPD request */
|
||||||
struct httpd_req_aux hd_req_aux; /*!< Additional data about the HTTPD request kept unexposed */
|
struct httpd_req_aux hd_req_aux; /*!< Additional data about the HTTPD request kept unexposed */
|
||||||
|
|
||||||
|
/* Array of registered error handler functions */
|
||||||
|
httpd_err_handler_func_t *err_handler_fns;
|
||||||
};
|
};
|
||||||
|
|
||||||
/******************* Group : Session Management ********************/
|
/******************* Group : Session Management ********************/
|
||||||
@@ -204,7 +149,7 @@ void httpd_sess_init(struct httpd_data *hd);
|
|||||||
* @param[in] newfd Descriptor of the new client to be added to the session.
|
* @param[in] newfd Descriptor of the new client to be added to the session.
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - ESP_OK : on successfully queueing the work
|
* - ESP_OK : on successfully queuing the work
|
||||||
* - ESP_FAIL : in case of control socket error while sending
|
* - ESP_FAIL : in case of control socket error while sending
|
||||||
*/
|
*/
|
||||||
esp_err_t httpd_sess_new(struct httpd_data *hd, int newfd);
|
esp_err_t httpd_sess_new(struct httpd_data *hd, int newfd);
|
||||||
@@ -226,7 +171,7 @@ esp_err_t httpd_sess_process(struct httpd_data *hd, int clifd);
|
|||||||
* and close the connection for this client.
|
* and close the connection for this client.
|
||||||
*
|
*
|
||||||
* @note The returned descriptor should be used by httpd_sess_iterate()
|
* @note The returned descriptor should be used by httpd_sess_iterate()
|
||||||
* to continue the iteration correctly. This ensurs that the
|
* to continue the iteration correctly. This ensures that the
|
||||||
* iteration is not restarted abruptly which may cause reading from
|
* iteration is not restarted abruptly which may cause reading from
|
||||||
* a socket which has been already processed and thus blocking
|
* a socket which has been already processed and thus blocking
|
||||||
* the server loop until data appears on that socket.
|
* the server loop until data appears on that socket.
|
||||||
@@ -249,7 +194,7 @@ int httpd_sess_delete(struct httpd_data *hd, int clifd);
|
|||||||
void httpd_sess_free_ctx(void *ctx, httpd_free_ctx_fn_t free_fn);
|
void httpd_sess_free_ctx(void *ctx, httpd_free_ctx_fn_t free_fn);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Add descriptors present in the socket database to an fd_set and
|
* @brief Add descriptors present in the socket database to an fdset and
|
||||||
* update the value of maxfd which are needed by the select function
|
* update the value of maxfd which are needed by the select function
|
||||||
* for looking through all available sockets for incoming data.
|
* for looking through all available sockets for incoming data.
|
||||||
*
|
*
|
||||||
@@ -288,12 +233,12 @@ bool httpd_is_sess_available(struct httpd_data *hd);
|
|||||||
* @brief Checks if session has any pending data/packets
|
* @brief Checks if session has any pending data/packets
|
||||||
* for processing
|
* for processing
|
||||||
*
|
*
|
||||||
* This is needed as httpd_unrecv may unreceive next
|
* This is needed as httpd_unrecv may un-receive next
|
||||||
* packet in the stream. If only partial packet was
|
* packet in the stream. If only partial packet was
|
||||||
* received then select() would mark the fd for processing
|
* received then select() would mark the fd for processing
|
||||||
* as remaining part of the packet would still be in socket
|
* as remaining part of the packet would still be in socket
|
||||||
* recv queue. But if a complete packet got unreceived
|
* recv queue. But if a complete packet got unreceived
|
||||||
* then it would not be processed until furtur data is
|
* then it would not be processed until further data is
|
||||||
* received on the socket. This is when this function
|
* received on the socket. This is when this function
|
||||||
* comes in use, as it checks the socket's pending data
|
* comes in use, as it checks the socket's pending data
|
||||||
* buffer.
|
* buffer.
|
||||||
@@ -343,7 +288,7 @@ esp_err_t httpd_sess_close_lru(struct httpd_data *hd);
|
|||||||
esp_err_t httpd_uri(struct httpd_data *hd);
|
esp_err_t httpd_uri(struct httpd_data *hd);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief Deregister all URI handlers
|
* @brief Unregister all URI handlers
|
||||||
*
|
*
|
||||||
* @param[in] hd Server instance data
|
* @param[in] hd Server instance data
|
||||||
*/
|
*/
|
||||||
@@ -353,7 +298,7 @@ void httpd_unregister_all_uri_handlers(struct httpd_data *hd);
|
|||||||
* @brief Validates the request to prevent users from calling APIs, that are to
|
* @brief Validates the request to prevent users from calling APIs, that are to
|
||||||
* be called only inside a URI handler, outside the handler context
|
* be called only inside a URI handler, outside the handler context
|
||||||
*
|
*
|
||||||
* @param[in] req Pointer to HTTP request that neds to be validated
|
* @param[in] req Pointer to HTTP request that needs to be validated
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
* - true : if valid request
|
* - true : if valid request
|
||||||
@@ -363,7 +308,7 @@ bool httpd_validate_req_ptr(httpd_req_t *r);
|
|||||||
|
|
||||||
/* httpd_validate_req_ptr() adds some overhead to frequently used APIs,
|
/* httpd_validate_req_ptr() adds some overhead to frequently used APIs,
|
||||||
* and is useful mostly for debugging, so it's preferable to disable
|
* and is useful mostly for debugging, so it's preferable to disable
|
||||||
* the check by defaut and enable it only if necessary */
|
* the check by default and enable it only if necessary */
|
||||||
#ifdef CONFIG_HTTPD_VALIDATE_REQ
|
#ifdef CONFIG_HTTPD_VALIDATE_REQ
|
||||||
#define httpd_valid_req(r) httpd_validate_req_ptr(r)
|
#define httpd_valid_req(r) httpd_validate_req_ptr(r)
|
||||||
#else
|
#else
|
||||||
@@ -409,6 +354,19 @@ esp_err_t httpd_req_new(struct httpd_data *hd, struct sock_db *sd);
|
|||||||
*/
|
*/
|
||||||
esp_err_t httpd_req_delete(struct httpd_data *hd);
|
esp_err_t httpd_req_delete(struct httpd_data *hd);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* @brief For handling HTTP errors by invoking registered
|
||||||
|
* error handler function
|
||||||
|
*
|
||||||
|
* @param[in] req Pointer to the HTTP request for which error occurred
|
||||||
|
* @param[in] error Error type
|
||||||
|
*
|
||||||
|
* @return
|
||||||
|
* - ESP_OK : error handled successful
|
||||||
|
* - ESP_FAIL : failure indicates that the underlying socket needs to be closed
|
||||||
|
*/
|
||||||
|
esp_err_t httpd_req_handle_err(httpd_req_t *req, httpd_err_code_t error);
|
||||||
|
|
||||||
/** End of Group : Parsing
|
/** End of Group : Parsing
|
||||||
* @}
|
* @}
|
||||||
*/
|
*/
|
||||||
@@ -419,22 +377,10 @@ esp_err_t httpd_req_delete(struct httpd_data *hd);
|
|||||||
* @{
|
* @{
|
||||||
*/
|
*/
|
||||||
|
|
||||||
/**
|
|
||||||
* @brief For sending out error code in response to HTTP request.
|
|
||||||
*
|
|
||||||
* @param[in] req Pointer to the HTTP request for which the resonse needs to be sent
|
|
||||||
* @param[in] error Error type to send
|
|
||||||
*
|
|
||||||
* @return
|
|
||||||
* - ESP_OK : if successful
|
|
||||||
* - ESP_FAIL : if failed
|
|
||||||
*/
|
|
||||||
esp_err_t httpd_resp_send_err(httpd_req_t *req, httpd_err_resp_t error);
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @brief For sending out data in response to an HTTP request.
|
* @brief For sending out data in response to an HTTP request.
|
||||||
*
|
*
|
||||||
* @param[in] req Pointer to the HTTP request for which the resonse needs to be sent
|
* @param[in] req Pointer to the HTTP request for which the response needs to be sent
|
||||||
* @param[in] buf Pointer to the buffer from where the body of the response is taken
|
* @param[in] buf Pointer to the buffer from where the body of the response is taken
|
||||||
* @param[in] buf_len Length of the buffer
|
* @param[in] buf_len Length of the buffer
|
||||||
*
|
*
|
||||||
@@ -457,7 +403,7 @@ int httpd_send(httpd_req_t *req, const char *buf, size_t buf_len);
|
|||||||
* @param[in] req Pointer to new HTTP request which only has the socket descriptor
|
* @param[in] req Pointer to new HTTP request which only has the socket descriptor
|
||||||
* @param[out] buf Pointer to the buffer which will be filled with the received data
|
* @param[out] buf Pointer to the buffer which will be filled with the received data
|
||||||
* @param[in] buf_len Length of the buffer
|
* @param[in] buf_len Length of the buffer
|
||||||
* @param[in] halt_after_pending When set true, halts immediatly after receiving from
|
* @param[in] halt_after_pending When set true, halts immediately after receiving from
|
||||||
* pending buffer
|
* pending buffer
|
||||||
*
|
*
|
||||||
* @return
|
* @return
|
||||||
|
@@ -288,21 +288,36 @@ static struct httpd_data *httpd_create(const httpd_config_t *config)
|
|||||||
{
|
{
|
||||||
/* Allocate memory for httpd instance data */
|
/* Allocate memory for httpd instance data */
|
||||||
struct httpd_data *hd = calloc(1, sizeof(struct httpd_data));
|
struct httpd_data *hd = calloc(1, sizeof(struct httpd_data));
|
||||||
if (hd != NULL) {
|
if (!hd) {
|
||||||
|
ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP server instance"));
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
hd->hd_calls = calloc(config->max_uri_handlers, sizeof(httpd_uri_t *));
|
hd->hd_calls = calloc(config->max_uri_handlers, sizeof(httpd_uri_t *));
|
||||||
if (hd->hd_calls == NULL) {
|
if (!hd->hd_calls) {
|
||||||
|
ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP URI handlers"));
|
||||||
free(hd);
|
free(hd);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
hd->hd_sd = calloc(config->max_open_sockets, sizeof(struct sock_db));
|
hd->hd_sd = calloc(config->max_open_sockets, sizeof(struct sock_db));
|
||||||
if (hd->hd_sd == NULL) {
|
if (!hd->hd_sd) {
|
||||||
|
ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP session data"));
|
||||||
free(hd->hd_calls);
|
free(hd->hd_calls);
|
||||||
free(hd);
|
free(hd);
|
||||||
return NULL;
|
return NULL;
|
||||||
}
|
}
|
||||||
struct httpd_req_aux *ra = &hd->hd_req_aux;
|
struct httpd_req_aux *ra = &hd->hd_req_aux;
|
||||||
ra->resp_hdrs = calloc(config->max_resp_headers, sizeof(struct resp_hdr));
|
ra->resp_hdrs = calloc(config->max_resp_headers, sizeof(struct resp_hdr));
|
||||||
if (ra->resp_hdrs == NULL) {
|
if (!ra->resp_hdrs) {
|
||||||
|
ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP response headers"));
|
||||||
|
free(hd->hd_sd);
|
||||||
|
free(hd->hd_calls);
|
||||||
|
free(hd);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
hd->err_handler_fns = calloc(HTTPD_ERR_CODE_MAX, sizeof(httpd_err_handler_func_t));
|
||||||
|
if (!hd->err_handler_fns) {
|
||||||
|
ESP_LOGE(TAG, LOG_FMT("Failed to allocate memory for HTTP error handlers"));
|
||||||
|
free(ra->resp_hdrs);
|
||||||
free(hd->hd_sd);
|
free(hd->hd_sd);
|
||||||
free(hd->hd_calls);
|
free(hd->hd_calls);
|
||||||
free(hd);
|
free(hd);
|
||||||
@@ -310,9 +325,6 @@ static struct httpd_data *httpd_create(const httpd_config_t *config)
|
|||||||
}
|
}
|
||||||
/* Save the configuration for this instance */
|
/* Save the configuration for this instance */
|
||||||
hd->config = *config;
|
hd->config = *config;
|
||||||
} else {
|
|
||||||
ESP_LOGE(TAG, "mem alloc failed");
|
|
||||||
}
|
|
||||||
return hd;
|
return hd;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -320,6 +332,7 @@ static void httpd_delete(struct httpd_data *hd)
|
|||||||
{
|
{
|
||||||
struct httpd_req_aux *ra = &hd->hd_req_aux;
|
struct httpd_req_aux *ra = &hd->hd_req_aux;
|
||||||
/* Free memory of httpd instance data */
|
/* Free memory of httpd instance data */
|
||||||
|
free(hd->err_handler_fns);
|
||||||
free(ra->resp_hdrs);
|
free(ra->resp_hdrs);
|
||||||
free(hd->hd_sd);
|
free(hd->hd_sd);
|
||||||
|
|
||||||
|
@@ -46,7 +46,7 @@ typedef struct {
|
|||||||
} status;
|
} status;
|
||||||
|
|
||||||
/* Response error code in case of PARSING_FAILED */
|
/* Response error code in case of PARSING_FAILED */
|
||||||
httpd_err_resp_t error;
|
httpd_err_code_t error;
|
||||||
|
|
||||||
/* For storing last callback parameters */
|
/* For storing last callback parameters */
|
||||||
struct {
|
struct {
|
||||||
@@ -81,7 +81,6 @@ static esp_err_t verify_url (http_parser *parser)
|
|||||||
ESP_LOGW(TAG, LOG_FMT("URI length (%d) greater than supported (%d)"),
|
ESP_LOGW(TAG, LOG_FMT("URI length (%d) greater than supported (%d)"),
|
||||||
length, sizeof(r->uri));
|
length, sizeof(r->uri));
|
||||||
parser_data->error = HTTPD_414_URI_TOO_LONG;
|
parser_data->error = HTTPD_414_URI_TOO_LONG;
|
||||||
parser_data->status = PARSING_FAILED;
|
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -128,6 +127,7 @@ static esp_err_t cb_url(http_parser *parser,
|
|||||||
parser_data->status = PARSING_URL;
|
parser_data->status = PARSING_URL;
|
||||||
} else if (parser_data->status != PARSING_URL) {
|
} else if (parser_data->status != PARSING_URL) {
|
||||||
ESP_LOGE(TAG, LOG_FMT("unexpected state transition"));
|
ESP_LOGE(TAG, LOG_FMT("unexpected state transition"));
|
||||||
|
parser_data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
|
||||||
parser_data->status = PARSING_FAILED;
|
parser_data->status = PARSING_FAILED;
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
@@ -194,6 +194,9 @@ static esp_err_t cb_header_field(http_parser *parser, const char *at, size_t len
|
|||||||
/* Check previous status */
|
/* Check previous status */
|
||||||
if (parser_data->status == PARSING_URL) {
|
if (parser_data->status == PARSING_URL) {
|
||||||
if (verify_url(parser) != ESP_OK) {
|
if (verify_url(parser) != ESP_OK) {
|
||||||
|
/* verify_url would already have set the
|
||||||
|
* error field of parser data, so only setting
|
||||||
|
* status to failed */
|
||||||
parser_data->status = PARSING_FAILED;
|
parser_data->status = PARSING_FAILED;
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
@@ -207,6 +210,7 @@ static esp_err_t cb_header_field(http_parser *parser, const char *at, size_t len
|
|||||||
|
|
||||||
/* Stop parsing for now and give control to process */
|
/* Stop parsing for now and give control to process */
|
||||||
if (pause_parsing(parser, at) != ESP_OK) {
|
if (pause_parsing(parser, at) != ESP_OK) {
|
||||||
|
parser_data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
|
||||||
parser_data->status = PARSING_FAILED;
|
parser_data->status = PARSING_FAILED;
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
@@ -221,6 +225,7 @@ static esp_err_t cb_header_field(http_parser *parser, const char *at, size_t len
|
|||||||
parser_data->status = PARSING_HDR_FIELD;
|
parser_data->status = PARSING_HDR_FIELD;
|
||||||
} else if (parser_data->status != PARSING_HDR_FIELD) {
|
} else if (parser_data->status != PARSING_HDR_FIELD) {
|
||||||
ESP_LOGE(TAG, LOG_FMT("unexpected state transition"));
|
ESP_LOGE(TAG, LOG_FMT("unexpected state transition"));
|
||||||
|
parser_data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
|
||||||
parser_data->status = PARSING_FAILED;
|
parser_data->status = PARSING_FAILED;
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
@@ -251,6 +256,7 @@ static esp_err_t cb_header_value(http_parser *parser, const char *at, size_t len
|
|||||||
ra->req_hdrs_count++;
|
ra->req_hdrs_count++;
|
||||||
} else if (parser_data->status != PARSING_HDR_VALUE) {
|
} else if (parser_data->status != PARSING_HDR_VALUE) {
|
||||||
ESP_LOGE(TAG, LOG_FMT("unexpected state transition"));
|
ESP_LOGE(TAG, LOG_FMT("unexpected state transition"));
|
||||||
|
parser_data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
|
||||||
parser_data->status = PARSING_FAILED;
|
parser_data->status = PARSING_FAILED;
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
@@ -275,6 +281,9 @@ static esp_err_t cb_headers_complete(http_parser *parser)
|
|||||||
if (parser_data->status == PARSING_URL) {
|
if (parser_data->status == PARSING_URL) {
|
||||||
ESP_LOGD(TAG, LOG_FMT("no headers"));
|
ESP_LOGD(TAG, LOG_FMT("no headers"));
|
||||||
if (verify_url(parser) != ESP_OK) {
|
if (verify_url(parser) != ESP_OK) {
|
||||||
|
/* verify_url would already have set the
|
||||||
|
* error field of parser data, so only setting
|
||||||
|
* status to failed */
|
||||||
parser_data->status = PARSING_FAILED;
|
parser_data->status = PARSING_FAILED;
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
@@ -287,6 +296,7 @@ static esp_err_t cb_headers_complete(http_parser *parser)
|
|||||||
parser_data->last.at += parser_data->last.length;
|
parser_data->last.at += parser_data->last.length;
|
||||||
} else {
|
} else {
|
||||||
ESP_LOGE(TAG, LOG_FMT("unexpected state transition"));
|
ESP_LOGE(TAG, LOG_FMT("unexpected state transition"));
|
||||||
|
parser_data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
|
||||||
parser_data->status = PARSING_FAILED;
|
parser_data->status = PARSING_FAILED;
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
@@ -300,7 +310,9 @@ static esp_err_t cb_headers_complete(http_parser *parser)
|
|||||||
|
|
||||||
if (parser->upgrade) {
|
if (parser->upgrade) {
|
||||||
ESP_LOGW(TAG, LOG_FMT("upgrade from HTTP not supported"));
|
ESP_LOGW(TAG, LOG_FMT("upgrade from HTTP not supported"));
|
||||||
parser_data->error = HTTPD_XXX_UPGRADE_NOT_SUPPORTED;
|
/* There is no specific HTTP error code to notify the client that
|
||||||
|
* upgrade is not supported, thus sending 400 Bad Request */
|
||||||
|
parser_data->error = HTTPD_400_BAD_REQUEST;
|
||||||
parser_data->status = PARSING_FAILED;
|
parser_data->status = PARSING_FAILED;
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
@@ -320,6 +332,7 @@ static esp_err_t cb_on_body(http_parser *parser, const char *at, size_t length)
|
|||||||
/* Check previous status */
|
/* Check previous status */
|
||||||
if (parser_data->status != PARSING_BODY) {
|
if (parser_data->status != PARSING_BODY) {
|
||||||
ESP_LOGE(TAG, LOG_FMT("unexpected state transition"));
|
ESP_LOGE(TAG, LOG_FMT("unexpected state transition"));
|
||||||
|
parser_data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
|
||||||
parser_data->status = PARSING_FAILED;
|
parser_data->status = PARSING_FAILED;
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
@@ -329,6 +342,7 @@ static esp_err_t cb_on_body(http_parser *parser, const char *at, size_t length)
|
|||||||
* may reset the parser state and cause current
|
* may reset the parser state and cause current
|
||||||
* request packet to be lost */
|
* request packet to be lost */
|
||||||
if (pause_parsing(parser, at) != ESP_OK) {
|
if (pause_parsing(parser, at) != ESP_OK) {
|
||||||
|
parser_data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
|
||||||
parser_data->status = PARSING_FAILED;
|
parser_data->status = PARSING_FAILED;
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
@@ -352,11 +366,15 @@ static esp_err_t cb_no_body(http_parser *parser)
|
|||||||
if (parser_data->status == PARSING_URL) {
|
if (parser_data->status == PARSING_URL) {
|
||||||
ESP_LOGD(TAG, LOG_FMT("no headers"));
|
ESP_LOGD(TAG, LOG_FMT("no headers"));
|
||||||
if (verify_url(parser) != ESP_OK) {
|
if (verify_url(parser) != ESP_OK) {
|
||||||
|
/* verify_url would already have set the
|
||||||
|
* error field of parser data, so only setting
|
||||||
|
* status to failed */
|
||||||
parser_data->status = PARSING_FAILED;
|
parser_data->status = PARSING_FAILED;
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
} else if (parser_data->status != PARSING_BODY) {
|
} else if (parser_data->status != PARSING_BODY) {
|
||||||
ESP_LOGE(TAG, LOG_FMT("unexpected state transition"));
|
ESP_LOGE(TAG, LOG_FMT("unexpected state transition"));
|
||||||
|
parser_data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
|
||||||
parser_data->status = PARSING_FAILED;
|
parser_data->status = PARSING_FAILED;
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
@@ -369,6 +387,7 @@ static esp_err_t cb_no_body(http_parser *parser)
|
|||||||
* may reset the parser state and cause current
|
* may reset the parser state and cause current
|
||||||
* request packet to be lost */
|
* request packet to be lost */
|
||||||
if (pause_parsing(parser, at) != ESP_OK) {
|
if (pause_parsing(parser, at) != ESP_OK) {
|
||||||
|
parser_data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
|
||||||
parser_data->status = PARSING_FAILED;
|
parser_data->status = PARSING_FAILED;
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
@@ -396,13 +415,25 @@ static int read_block(httpd_req_t *req, size_t offset, size_t length)
|
|||||||
int nbytes = httpd_recv_with_opt(req, raux->scratch + offset, buf_len, true);
|
int nbytes = httpd_recv_with_opt(req, raux->scratch + offset, buf_len, true);
|
||||||
if (nbytes < 0) {
|
if (nbytes < 0) {
|
||||||
ESP_LOGD(TAG, LOG_FMT("error in httpd_recv"));
|
ESP_LOGD(TAG, LOG_FMT("error in httpd_recv"));
|
||||||
|
/* If timeout occurred allow the
|
||||||
|
* situation to be handled */
|
||||||
if (nbytes == HTTPD_SOCK_ERR_TIMEOUT) {
|
if (nbytes == HTTPD_SOCK_ERR_TIMEOUT) {
|
||||||
httpd_resp_send_err(req, HTTPD_408_REQ_TIMEOUT);
|
/* Invoke error handler which may return ESP_OK
|
||||||
|
* to signal for retrying call to recv(), else it may
|
||||||
|
* return ESP_FAIL to signal for closure of socket */
|
||||||
|
return (httpd_req_handle_err(req, HTTPD_408_REQ_TIMEOUT) == ESP_OK) ?
|
||||||
|
HTTPD_SOCK_ERR_TIMEOUT : HTTPD_SOCK_ERR_FAIL;
|
||||||
}
|
}
|
||||||
return -1;
|
/* Some socket error occurred. Return failure
|
||||||
|
* to force closure of underlying socket.
|
||||||
|
* Error message is not sent as socket may not
|
||||||
|
* be valid anymore */
|
||||||
|
return HTTPD_SOCK_ERR_FAIL;
|
||||||
} else if (nbytes == 0) {
|
} else if (nbytes == 0) {
|
||||||
ESP_LOGD(TAG, LOG_FMT("connection closed"));
|
ESP_LOGD(TAG, LOG_FMT("connection closed"));
|
||||||
return -1;
|
/* Connection closed by client so no
|
||||||
|
* need to send error response */
|
||||||
|
return HTTPD_SOCK_ERR_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGD(TAG, LOG_FMT("received HTTP request block size = %d"), nbytes);
|
ESP_LOGD(TAG, LOG_FMT("received HTTP request block size = %d"), nbytes);
|
||||||
@@ -417,7 +448,11 @@ static int parse_block(http_parser *parser, size_t offset, size_t length)
|
|||||||
size_t nparsed = 0;
|
size_t nparsed = 0;
|
||||||
|
|
||||||
if (!length) {
|
if (!length) {
|
||||||
ESP_LOGW(TAG, LOG_FMT("response uri/header too big"));
|
/* Parsing is still happening but nothing to
|
||||||
|
* parse means no more space left on buffer,
|
||||||
|
* therefore it can be inferred that the
|
||||||
|
* request URI/header must be too long */
|
||||||
|
ESP_LOGW(TAG, LOG_FMT("request URI/header too long"));
|
||||||
switch (data->status) {
|
switch (data->status) {
|
||||||
case PARSING_URL:
|
case PARSING_URL:
|
||||||
data->error = HTTPD_414_URI_TOO_LONG;
|
data->error = HTTPD_414_URI_TOO_LONG;
|
||||||
@@ -425,14 +460,17 @@ static int parse_block(http_parser *parser, size_t offset, size_t length)
|
|||||||
case PARSING_HDR_FIELD:
|
case PARSING_HDR_FIELD:
|
||||||
case PARSING_HDR_VALUE:
|
case PARSING_HDR_VALUE:
|
||||||
data->error = HTTPD_431_REQ_HDR_FIELDS_TOO_LARGE;
|
data->error = HTTPD_431_REQ_HDR_FIELDS_TOO_LARGE;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
|
ESP_LOGE(TAG, LOG_FMT("unexpected state"));
|
||||||
|
data->error = HTTPD_500_INTERNAL_SERVER_ERROR;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
data->status = PARSING_FAILED;
|
data->status = PARSING_FAILED;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Unpause the parsing if paused */
|
/* Un-pause the parsing if paused */
|
||||||
if (data->paused) {
|
if (data->paused) {
|
||||||
nparsed = continue_parsing(parser, length);
|
nparsed = continue_parsing(parser, length);
|
||||||
length -= nparsed;
|
length -= nparsed;
|
||||||
@@ -448,6 +486,8 @@ static int parse_block(http_parser *parser, size_t offset, size_t length)
|
|||||||
|
|
||||||
/* Check state */
|
/* Check state */
|
||||||
if (data->status == PARSING_FAILED) {
|
if (data->status == PARSING_FAILED) {
|
||||||
|
/* It is expected that the error field of
|
||||||
|
* parser data should have been set by now */
|
||||||
ESP_LOGW(TAG, LOG_FMT("parsing failed"));
|
ESP_LOGW(TAG, LOG_FMT("parsing failed"));
|
||||||
return -1;
|
return -1;
|
||||||
} else if (data->paused) {
|
} else if (data->paused) {
|
||||||
@@ -457,8 +497,8 @@ static int parse_block(http_parser *parser, size_t offset, size_t length)
|
|||||||
return 0;
|
return 0;
|
||||||
} else if (nparsed != length) {
|
} else if (nparsed != length) {
|
||||||
/* http_parser error */
|
/* http_parser error */
|
||||||
data->status = PARSING_FAILED;
|
|
||||||
data->error = HTTPD_400_BAD_REQUEST;
|
data->error = HTTPD_400_BAD_REQUEST;
|
||||||
|
data->status = PARSING_FAILED;
|
||||||
ESP_LOGW(TAG, LOG_FMT("incomplete (%d/%d) with parser error = %d"),
|
ESP_LOGW(TAG, LOG_FMT("incomplete (%d/%d) with parser error = %d"),
|
||||||
nparsed, length, parser->http_errno);
|
nparsed, length, parser->http_errno);
|
||||||
return -1;
|
return -1;
|
||||||
@@ -508,7 +548,16 @@ static esp_err_t httpd_parse_req(struct httpd_data *hd)
|
|||||||
do {
|
do {
|
||||||
/* Read block into scratch buffer */
|
/* Read block into scratch buffer */
|
||||||
if ((blk_len = read_block(r, offset, PARSER_BLOCK_SIZE)) < 0) {
|
if ((blk_len = read_block(r, offset, PARSER_BLOCK_SIZE)) < 0) {
|
||||||
/* Return error to close socket */
|
if (blk_len == HTTPD_SOCK_ERR_TIMEOUT) {
|
||||||
|
/* Retry read in case of non-fatal timeout error.
|
||||||
|
* read_block() ensures that the timeout error is
|
||||||
|
* handled properly so that this doesn't get stuck
|
||||||
|
* in an infinite loop */
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
/* If not HTTPD_SOCK_ERR_TIMEOUT, returned error must
|
||||||
|
* be HTTPD_SOCK_ERR_FAIL which means we need to return
|
||||||
|
* failure and thereby close the underlying socket */
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -518,8 +567,10 @@ static esp_err_t httpd_parse_req(struct httpd_data *hd)
|
|||||||
|
|
||||||
/* Parse data block from buffer */
|
/* Parse data block from buffer */
|
||||||
if ((offset = parse_block(&parser, offset, blk_len)) < 0) {
|
if ((offset = parse_block(&parser, offset, blk_len)) < 0) {
|
||||||
/* Server/Client error. Send error code as response status */
|
/* HTTP error occurred.
|
||||||
return httpd_resp_send_err(r, parser_data.error);
|
* Send error code as response status and
|
||||||
|
* invoke error handler */
|
||||||
|
return httpd_req_handle_err(r, parser_data.error);
|
||||||
}
|
}
|
||||||
} while (parser_data.status != PARSING_COMPLETE);
|
} while (parser_data.status != PARSING_COMPLETE);
|
||||||
|
|
||||||
|
@@ -379,25 +379,12 @@ esp_err_t httpd_resp_send_chunk(httpd_req_t *r, const char *buf, ssize_t buf_len
|
|||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
esp_err_t httpd_resp_send_404(httpd_req_t *r)
|
esp_err_t httpd_resp_send_err(httpd_req_t *req, httpd_err_code_t error, const char *usr_msg)
|
||||||
{
|
|
||||||
return httpd_resp_send_err(r, HTTPD_404_NOT_FOUND);
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t httpd_resp_send_408(httpd_req_t *r)
|
|
||||||
{
|
|
||||||
return httpd_resp_send_err(r, HTTPD_408_REQ_TIMEOUT);
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t httpd_resp_send_500(httpd_req_t *r)
|
|
||||||
{
|
|
||||||
return httpd_resp_send_err(r, HTTPD_500_SERVER_ERROR);
|
|
||||||
}
|
|
||||||
|
|
||||||
esp_err_t httpd_resp_send_err(httpd_req_t *req, httpd_err_resp_t error)
|
|
||||||
{
|
{
|
||||||
|
esp_err_t ret;
|
||||||
const char *msg;
|
const char *msg;
|
||||||
const char *status;
|
const char *status;
|
||||||
|
|
||||||
switch (error) {
|
switch (error) {
|
||||||
case HTTPD_501_METHOD_NOT_IMPLEMENTED:
|
case HTTPD_501_METHOD_NOT_IMPLEMENTED:
|
||||||
status = "501 Method Not Implemented";
|
status = "501 Method Not Implemented";
|
||||||
@@ -413,7 +400,7 @@ esp_err_t httpd_resp_send_err(httpd_req_t *req, httpd_err_resp_t error)
|
|||||||
break;
|
break;
|
||||||
case HTTPD_404_NOT_FOUND:
|
case HTTPD_404_NOT_FOUND:
|
||||||
status = "404 Not Found";
|
status = "404 Not Found";
|
||||||
msg = "This URI doesn't exist";
|
msg = "This URI does not exist";
|
||||||
break;
|
break;
|
||||||
case HTTPD_405_METHOD_NOT_ALLOWED:
|
case HTTPD_405_METHOD_NOT_ALLOWED:
|
||||||
status = "405 Method Not Allowed";
|
status = "405 Method Not Allowed";
|
||||||
@@ -435,22 +422,85 @@ esp_err_t httpd_resp_send_err(httpd_req_t *req, httpd_err_resp_t error)
|
|||||||
status = "431 Request Header Fields Too Large";
|
status = "431 Request Header Fields Too Large";
|
||||||
msg = "Header fields are too long for server to interpret";
|
msg = "Header fields are too long for server to interpret";
|
||||||
break;
|
break;
|
||||||
case HTTPD_XXX_UPGRADE_NOT_SUPPORTED:
|
case HTTPD_500_INTERNAL_SERVER_ERROR:
|
||||||
/* If the server does not support upgrade, or is unable to upgrade
|
|
||||||
* it responds with a standard HTTP/1.1 response */
|
|
||||||
status = "200 OK";
|
|
||||||
msg = "Upgrade not supported by server";
|
|
||||||
break;
|
|
||||||
case HTTPD_500_SERVER_ERROR:
|
|
||||||
default:
|
default:
|
||||||
status = "500 Server Error";
|
status = "500 Internal Server Error";
|
||||||
msg = "Server has encountered an unexpected error";
|
msg = "Server has encountered an unexpected error";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* If user has provided custom message, override default message */
|
||||||
|
msg = usr_msg ? usr_msg : msg;
|
||||||
ESP_LOGW(TAG, LOG_FMT("%s - %s"), status, msg);
|
ESP_LOGW(TAG, LOG_FMT("%s - %s"), status, msg);
|
||||||
|
|
||||||
httpd_resp_set_status (req, status);
|
/* Set error code in HTTP response */
|
||||||
httpd_resp_set_type (req, HTTPD_TYPE_TEXT);
|
httpd_resp_set_status(req, status);
|
||||||
return httpd_resp_send (req, msg, strlen(msg));
|
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 */
|
||||||
|
ret = httpd_resp_send(req, msg, strlen(msg));
|
||||||
|
|
||||||
|
#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)
|
||||||
|
{
|
||||||
|
if (handle == NULL || error >= HTTPD_ERR_CODE_MAX) {
|
||||||
|
return ESP_ERR_INVALID_ARG;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct httpd_data *hd = (struct httpd_data *) handle;
|
||||||
|
hd->err_handler_fns[error] = err_handler_fn;
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t httpd_req_handle_err(httpd_req_t *req, httpd_err_code_t error)
|
||||||
|
{
|
||||||
|
struct httpd_data *hd = (struct httpd_data *) req->handle;
|
||||||
|
esp_err_t ret;
|
||||||
|
|
||||||
|
/* Invoke custom error handler if configured */
|
||||||
|
if (hd->err_handler_fns[error]) {
|
||||||
|
ret = hd->err_handler_fns[error](req, error);
|
||||||
|
|
||||||
|
/* If error code is 500, force return failure
|
||||||
|
* irrespective of the handler's return value */
|
||||||
|
ret = (error == HTTPD_500_INTERNAL_SERVER_ERROR ? ESP_FAIL : ret);
|
||||||
|
} else {
|
||||||
|
/* If no handler is registered for this error default
|
||||||
|
* behavior is to send the HTTP error response and
|
||||||
|
* return failure for closure of underlying socket */
|
||||||
|
httpd_resp_send_err(req, error, NULL);
|
||||||
|
ret = ESP_FAIL;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
int httpd_req_recv(httpd_req_t *r, char *buf, size_t buf_len)
|
int httpd_req_recv(httpd_req_t *r, char *buf, size_t buf_len)
|
||||||
|
@@ -93,7 +93,7 @@ bool httpd_uri_match_wildcard(const char *template, const char *uri, size_t len)
|
|||||||
static httpd_uri_t* httpd_find_uri_handler(struct httpd_data *hd,
|
static httpd_uri_t* httpd_find_uri_handler(struct httpd_data *hd,
|
||||||
const char *uri, size_t uri_len,
|
const char *uri, size_t uri_len,
|
||||||
httpd_method_t method,
|
httpd_method_t method,
|
||||||
httpd_err_resp_t *err)
|
httpd_err_code_t *err)
|
||||||
{
|
{
|
||||||
if (err) {
|
if (err) {
|
||||||
*err = HTTPD_404_NOT_FOUND;
|
*err = HTTPD_404_NOT_FOUND;
|
||||||
@@ -279,7 +279,7 @@ esp_err_t httpd_uri(struct httpd_data *hd)
|
|||||||
struct http_parser_url *res = &hd->hd_req_aux.url_parse_res;
|
struct http_parser_url *res = &hd->hd_req_aux.url_parse_res;
|
||||||
|
|
||||||
/* For conveying URI not found/method not allowed */
|
/* For conveying URI not found/method not allowed */
|
||||||
httpd_err_resp_t err = 0;
|
httpd_err_code_t err = 0;
|
||||||
|
|
||||||
ESP_LOGD(TAG, LOG_FMT("request for %s with type %d"), req->uri, req->method);
|
ESP_LOGD(TAG, LOG_FMT("request for %s with type %d"), req->uri, req->method);
|
||||||
|
|
||||||
@@ -294,11 +294,11 @@ esp_err_t httpd_uri(struct httpd_data *hd)
|
|||||||
switch (err) {
|
switch (err) {
|
||||||
case HTTPD_404_NOT_FOUND:
|
case HTTPD_404_NOT_FOUND:
|
||||||
ESP_LOGW(TAG, LOG_FMT("URI '%s' not found"), req->uri);
|
ESP_LOGW(TAG, LOG_FMT("URI '%s' not found"), req->uri);
|
||||||
return httpd_resp_send_err(req, HTTPD_404_NOT_FOUND);
|
return httpd_req_handle_err(req, HTTPD_404_NOT_FOUND);
|
||||||
case HTTPD_405_METHOD_NOT_ALLOWED:
|
case HTTPD_405_METHOD_NOT_ALLOWED:
|
||||||
ESP_LOGW(TAG, LOG_FMT("Method '%d' not allowed for URI '%s'"),
|
ESP_LOGW(TAG, LOG_FMT("Method '%d' not allowed for URI '%s'"),
|
||||||
req->method, req->uri);
|
req->method, req->uri);
|
||||||
return httpd_resp_send_err(req, HTTPD_405_METHOD_NOT_ALLOWED);
|
return httpd_req_handle_err(req, HTTPD_405_METHOD_NOT_ALLOWED);
|
||||||
default:
|
default:
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
@@ -95,6 +95,7 @@ typedef struct httpd_ssl_config httpd_ssl_config_t;
|
|||||||
.global_transport_ctx_free_fn = NULL, \
|
.global_transport_ctx_free_fn = NULL, \
|
||||||
.open_fn = NULL, \
|
.open_fn = NULL, \
|
||||||
.close_fn = NULL, \
|
.close_fn = NULL, \
|
||||||
|
.uri_match_fn = NULL \
|
||||||
}, \
|
}, \
|
||||||
.cacert_pem = NULL, \
|
.cacert_pem = NULL, \
|
||||||
.cacert_len = 0, \
|
.cacert_len = 0, \
|
||||||
|
@@ -55,6 +55,7 @@ esp_err_t echo_post_handler(httpd_req_t *req)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
if (!buf) {
|
if (!buf) {
|
||||||
|
ESP_LOGE(TAG, "Failed to allocate memory of %d bytes!", req->content_len + 1);
|
||||||
httpd_resp_send_500(req);
|
httpd_resp_send_500(req);
|
||||||
return ESP_FAIL;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
@@ -84,13 +85,16 @@ esp_err_t echo_post_handler(httpd_req_t *req)
|
|||||||
if (hdr_len) {
|
if (hdr_len) {
|
||||||
/* Read Custom header value */
|
/* Read Custom header value */
|
||||||
req_hdr = malloc(hdr_len + 1);
|
req_hdr = malloc(hdr_len + 1);
|
||||||
if (req_hdr) {
|
if (!req_hdr) {
|
||||||
|
ESP_LOGE(TAG, "Failed to allocate memory of %d bytes!", hdr_len + 1);
|
||||||
|
httpd_resp_send_500(req);
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
httpd_req_get_hdr_value_str(req, "Custom", req_hdr, hdr_len + 1);
|
httpd_req_get_hdr_value_str(req, "Custom", req_hdr, hdr_len + 1);
|
||||||
|
|
||||||
/* Set as additional header for response packet */
|
/* Set as additional header for response packet */
|
||||||
httpd_resp_set_hdr(req, "Custom", req_hdr);
|
httpd_resp_set_hdr(req, "Custom", req_hdr);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
httpd_resp_send(req, buf, req->content_len);
|
httpd_resp_send(req, buf, req->content_len);
|
||||||
free (req_hdr);
|
free (req_hdr);
|
||||||
free (buf);
|
free (buf);
|
||||||
|
@@ -367,7 +367,7 @@ def put_hello(dut, port):
|
|||||||
|
|
||||||
def post_hello(dut, port):
|
def post_hello(dut, port):
|
||||||
# POST /hello returns 405'
|
# POST /hello returns 405'
|
||||||
Utility.console_log("[test] POST /hello returns 404 =>", end=' ')
|
Utility.console_log("[test] POST /hello returns 405 =>", end=' ')
|
||||||
conn = http.client.HTTPConnection(dut, int(port), timeout=15)
|
conn = http.client.HTTPConnection(dut, int(port), timeout=15)
|
||||||
conn.request("POST", "/hello", "Hello")
|
conn.request("POST", "/hello", "Hello")
|
||||||
resp = conn.getresponse()
|
resp = conn.getresponse()
|
||||||
@@ -541,8 +541,10 @@ def leftover_data_test(dut, port):
|
|||||||
if not test_val("False URI Status", str(404), str(resp.status)):
|
if not test_val("False URI Status", str(404), str(resp.status)):
|
||||||
s.close()
|
s.close()
|
||||||
return False
|
return False
|
||||||
resp.read()
|
# socket would have been closed by server due to error
|
||||||
|
s.close()
|
||||||
|
|
||||||
|
s = http.client.HTTPConnection(dut + ":" + port, timeout=15)
|
||||||
s.request("GET", url='/hello')
|
s.request("GET", url='/hello')
|
||||||
resp = s.getresponse()
|
resp = s.getresponse()
|
||||||
if not test_val("Hello World Data", "Hello World!", resp.read().decode()):
|
if not test_val("Hello World Data", "Hello World!", resp.read().decode()):
|
||||||
@@ -637,7 +639,7 @@ def code_500_server_error_test(dut, port):
|
|||||||
Utility.console_log("[test] 500 Server Error test =>", end=' ')
|
Utility.console_log("[test] 500 Server Error test =>", end=' ')
|
||||||
s = Session(dut, port)
|
s = Session(dut, port)
|
||||||
# Sending a very large content length will cause malloc to fail
|
# Sending a very large content length will cause malloc to fail
|
||||||
content_len = 2**31
|
content_len = 2**30
|
||||||
s.client.sendall(("POST /echo HTTP/1.1\r\nHost: " + dut + "\r\nContent-Length: " + str(content_len) + "\r\n\r\nABCD").encode())
|
s.client.sendall(("POST /echo HTTP/1.1\r\nHost: " + dut + "\r\nContent-Length: " + str(content_len) + "\r\n\r\nABCD").encode())
|
||||||
s.read_resp_hdrs()
|
s.read_resp_hdrs()
|
||||||
s.read_resp_data()
|
s.read_resp_data()
|
||||||
@@ -802,7 +804,7 @@ def send_postx_hdr_len(dut, port, length):
|
|||||||
hdr = s.read_resp_hdrs()
|
hdr = s.read_resp_hdrs()
|
||||||
resp = s.read_resp_data()
|
resp = s.read_resp_data()
|
||||||
s.close()
|
s.close()
|
||||||
if "Custom" in hdr:
|
if hdr and ("Custom" in hdr):
|
||||||
return (hdr["Custom"] == custom_hdr_val), resp
|
return (hdr["Custom"] == custom_hdr_val), resp
|
||||||
return False, s.status
|
return False, s.status
|
||||||
|
|
||||||
@@ -826,7 +828,7 @@ def test_upgrade_not_supported(dut, port):
|
|||||||
s.client.sendall(("OPTIONS * HTTP/1.1\r\nHost:" + dut + "\r\nUpgrade: TLS/1.0\r\nConnection: Upgrade\r\n\r\n").encode())
|
s.client.sendall(("OPTIONS * HTTP/1.1\r\nHost:" + dut + "\r\nUpgrade: TLS/1.0\r\nConnection: Upgrade\r\n\r\n").encode())
|
||||||
s.read_resp_hdrs()
|
s.read_resp_hdrs()
|
||||||
s.read_resp_data()
|
s.read_resp_data()
|
||||||
if not test_val("Client Error", "200", s.status):
|
if not test_val("Client Error", "400", s.status):
|
||||||
s.close()
|
s.close()
|
||||||
return False
|
return False
|
||||||
s.close()
|
s.close()
|
||||||
|
@@ -72,9 +72,10 @@ static esp_err_t http_resp_dir_html(httpd_req_t *req)
|
|||||||
const size_t entrypath_offset = strlen(fullpath);
|
const size_t entrypath_offset = strlen(fullpath);
|
||||||
|
|
||||||
if (!dir) {
|
if (!dir) {
|
||||||
/* If opening directory failed then send 404 server error */
|
ESP_LOGE(TAG, "Failed to stat dir : %s", fullpath);
|
||||||
httpd_resp_send_404(req);
|
/* Respond with 404 Not Found */
|
||||||
return ESP_OK;
|
httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "Directory does not exist");
|
||||||
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Send HTML file header */
|
/* Send HTML file header */
|
||||||
@@ -172,18 +173,17 @@ static esp_err_t http_resp_file(httpd_req_t *req)
|
|||||||
strcat(filepath, req->uri);
|
strcat(filepath, req->uri);
|
||||||
if (stat(filepath, &file_stat) == -1) {
|
if (stat(filepath, &file_stat) == -1) {
|
||||||
ESP_LOGE(TAG, "Failed to stat file : %s", filepath);
|
ESP_LOGE(TAG, "Failed to stat file : %s", filepath);
|
||||||
/* If file doesn't exist respond with 404 Not Found */
|
/* Respond with 404 Not Found */
|
||||||
httpd_resp_send_404(req);
|
httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "File does not exist");
|
||||||
return ESP_OK;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
fd = fopen(filepath, "r");
|
fd = fopen(filepath, "r");
|
||||||
if (!fd) {
|
if (!fd) {
|
||||||
ESP_LOGE(TAG, "Failed to read existing file : %s", filepath);
|
ESP_LOGE(TAG, "Failed to read existing file : %s", filepath);
|
||||||
/* If file exists but unable to open respond with 500 Server Error */
|
/* Respond with 500 Internal Server Error */
|
||||||
httpd_resp_set_status(req, "500 Server Error");
|
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to read existing file");
|
||||||
httpd_resp_sendstr(req, "Failed to read existing file!");
|
return ESP_FAIL;
|
||||||
return ESP_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Sending file : %s (%ld bytes)...", filepath, file_stat.st_size);
|
ESP_LOGI(TAG, "Sending file : %s (%ld bytes)...", filepath, file_stat.st_size);
|
||||||
@@ -202,10 +202,9 @@ static esp_err_t http_resp_file(httpd_req_t *req)
|
|||||||
ESP_LOGE(TAG, "File sending failed!");
|
ESP_LOGE(TAG, "File sending failed!");
|
||||||
/* Abort sending file */
|
/* Abort sending file */
|
||||||
httpd_resp_sendstr_chunk(req, NULL);
|
httpd_resp_sendstr_chunk(req, NULL);
|
||||||
/* Send error message with status code */
|
/* Respond with 500 Internal Server Error */
|
||||||
httpd_resp_set_status(req, "500 Server Error");
|
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to send file");
|
||||||
httpd_resp_sendstr(req, "Failed to send file!");
|
return ESP_FAIL;
|
||||||
return ESP_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Keep looping till the whole file is sent */
|
/* Keep looping till the whole file is sent */
|
||||||
@@ -249,10 +248,8 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
|
|||||||
if (strlen(filename) == 0 || filename[strlen(filename) - 1] == '/') {
|
if (strlen(filename) == 0 || filename[strlen(filename) - 1] == '/') {
|
||||||
ESP_LOGE(TAG, "Invalid file name : %s", filename);
|
ESP_LOGE(TAG, "Invalid file name : %s", filename);
|
||||||
/* Respond with 400 Bad Request */
|
/* Respond with 400 Bad Request */
|
||||||
httpd_resp_set_status(req, "400 Bad Request");
|
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid file name");
|
||||||
/* Send failure reason */
|
return ESP_FAIL;
|
||||||
httpd_resp_sendstr(req, "Invalid file name!");
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Retrieve the base path of file storage to construct the full path */
|
/* Retrieve the base path of file storage to construct the full path */
|
||||||
@@ -262,17 +259,17 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
|
|||||||
strcat(filepath, filename);
|
strcat(filepath, filename);
|
||||||
if (stat(filepath, &file_stat) == 0) {
|
if (stat(filepath, &file_stat) == 0) {
|
||||||
ESP_LOGE(TAG, "File already exists : %s", filepath);
|
ESP_LOGE(TAG, "File already exists : %s", filepath);
|
||||||
/* If file exists respond with 400 Bad Request */
|
/* Respond with 400 Bad Request */
|
||||||
httpd_resp_set_status(req, "400 Bad Request");
|
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "File already exists");
|
||||||
httpd_resp_sendstr(req, "File already exists!");
|
return ESP_FAIL;
|
||||||
return ESP_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* File cannot be larger than a limit */
|
/* File cannot be larger than a limit */
|
||||||
if (req->content_len > MAX_FILE_SIZE) {
|
if (req->content_len > MAX_FILE_SIZE) {
|
||||||
ESP_LOGE(TAG, "File too large : %d bytes", req->content_len);
|
ESP_LOGE(TAG, "File too large : %d bytes", req->content_len);
|
||||||
httpd_resp_set_status(req, "400 Bad Request");
|
/* Respond with 400 Bad Request */
|
||||||
httpd_resp_sendstr(req, "File size must be less than "
|
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST,
|
||||||
|
"File size must be less than "
|
||||||
MAX_FILE_SIZE_STR "!");
|
MAX_FILE_SIZE_STR "!");
|
||||||
/* Return failure to close underlying connection else the
|
/* Return failure to close underlying connection else the
|
||||||
* incoming file content will keep the socket busy */
|
* incoming file content will keep the socket busy */
|
||||||
@@ -282,10 +279,9 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
|
|||||||
fd = fopen(filepath, "w");
|
fd = fopen(filepath, "w");
|
||||||
if (!fd) {
|
if (!fd) {
|
||||||
ESP_LOGE(TAG, "Failed to create file : %s", filepath);
|
ESP_LOGE(TAG, "Failed to create file : %s", filepath);
|
||||||
/* If file creation failed, respond with 500 Server Error */
|
/* Respond with 500 Internal Server Error */
|
||||||
httpd_resp_set_status(req, "500 Server Error");
|
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to create file");
|
||||||
httpd_resp_sendstr(req, "Failed to create file!");
|
return ESP_FAIL;
|
||||||
return ESP_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Receiving file : %s...", filename);
|
ESP_LOGI(TAG, "Receiving file : %s...", filename);
|
||||||
@@ -314,10 +310,9 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
|
|||||||
unlink(filepath);
|
unlink(filepath);
|
||||||
|
|
||||||
ESP_LOGE(TAG, "File reception failed!");
|
ESP_LOGE(TAG, "File reception failed!");
|
||||||
/* Return failure reason with status code */
|
/* Respond with 500 Internal Server Error */
|
||||||
httpd_resp_set_status(req, "500 Server Error");
|
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to receive file");
|
||||||
httpd_resp_sendstr(req, "Failed to receive file!");
|
return ESP_FAIL;
|
||||||
return ESP_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Write buffer content to file on storage */
|
/* Write buffer content to file on storage */
|
||||||
@@ -328,9 +323,9 @@ static esp_err_t upload_post_handler(httpd_req_t *req)
|
|||||||
unlink(filepath);
|
unlink(filepath);
|
||||||
|
|
||||||
ESP_LOGE(TAG, "File write failed!");
|
ESP_LOGE(TAG, "File write failed!");
|
||||||
httpd_resp_set_status(req, "500 Server Error");
|
/* Respond with 500 Internal Server Error */
|
||||||
httpd_resp_sendstr(req, "Failed to write file to storage!");
|
httpd_resp_send_err(req, HTTPD_500_INTERNAL_SERVER_ERROR, "Failed to write file to storage");
|
||||||
return ESP_OK;
|
return ESP_FAIL;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Keep track of remaining size of
|
/* Keep track of remaining size of
|
||||||
@@ -363,10 +358,8 @@ static esp_err_t delete_post_handler(httpd_req_t *req)
|
|||||||
if (strlen(filename) == 0 || filename[strlen(filename) - 1] == '/') {
|
if (strlen(filename) == 0 || filename[strlen(filename) - 1] == '/') {
|
||||||
ESP_LOGE(TAG, "Invalid file name : %s", filename);
|
ESP_LOGE(TAG, "Invalid file name : %s", filename);
|
||||||
/* Respond with 400 Bad Request */
|
/* Respond with 400 Bad Request */
|
||||||
httpd_resp_set_status(req, "400 Bad Request");
|
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "Invalid file name");
|
||||||
/* Send failure reason */
|
return ESP_FAIL;
|
||||||
httpd_resp_sendstr(req, "Invalid file name!");
|
|
||||||
return ESP_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Retrieve the base path of file storage to construct the full path */
|
/* Retrieve the base path of file storage to construct the full path */
|
||||||
@@ -376,10 +369,9 @@ static esp_err_t delete_post_handler(httpd_req_t *req)
|
|||||||
strcat(filepath, filename);
|
strcat(filepath, filename);
|
||||||
if (stat(filepath, &file_stat) == -1) {
|
if (stat(filepath, &file_stat) == -1) {
|
||||||
ESP_LOGE(TAG, "File does not exist : %s", filename);
|
ESP_LOGE(TAG, "File does not exist : %s", filename);
|
||||||
/* If file does not exist respond with 400 Bad Request */
|
/* Respond with 400 Bad Request */
|
||||||
httpd_resp_set_status(req, "400 Bad Request");
|
httpd_resp_send_err(req, HTTPD_400_BAD_REQUEST, "File does not exist");
|
||||||
httpd_resp_sendstr(req, "File does not exist!");
|
return ESP_FAIL;
|
||||||
return ESP_OK;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
ESP_LOGI(TAG, "Deleting file : %s", filename);
|
ESP_LOGI(TAG, "Deleting file : %s", filename);
|
||||||
|
@@ -152,6 +152,33 @@ httpd_uri_t echo = {
|
|||||||
.user_ctx = NULL
|
.user_ctx = NULL
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* This handler allows the custom error handling functionality to be
|
||||||
|
* tested from client side. For that, when a PUT request 0 is sent to
|
||||||
|
* URI /ctrl, the /hello and /echo URIs are unregistered and following
|
||||||
|
* custom error handler http_404_error_handler() is registered.
|
||||||
|
* Afterwards, when /hello or /echo is requested, this custom error
|
||||||
|
* handler is invoked which, after sending an error message to client,
|
||||||
|
* either closes the underlying socket (when requested URI is /echo)
|
||||||
|
* or keeps it open (when requested URI is /hello). This allows the
|
||||||
|
* client to infer if the custom error handler is functioning as expected
|
||||||
|
* by observing the socket state.
|
||||||
|
*/
|
||||||
|
esp_err_t http_404_error_handler(httpd_req_t *req, httpd_err_code_t err)
|
||||||
|
{
|
||||||
|
if (strcmp("/hello", req->uri) == 0) {
|
||||||
|
httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "/hello URI is not available");
|
||||||
|
/* Return ESP_OK to keep underlying socket open */
|
||||||
|
return ESP_OK;
|
||||||
|
} else if (strcmp("/echo", req->uri) == 0) {
|
||||||
|
httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "/echo URI is not available");
|
||||||
|
/* Return ESP_FAIL to close underlying socket */
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
/* For any other URI send 404 and close socket */
|
||||||
|
httpd_resp_send_err(req, HTTPD_404_NOT_FOUND, "Some 404 error message");
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
/* An HTTP PUT handler. This demonstrates realtime
|
/* An HTTP PUT handler. This demonstrates realtime
|
||||||
* registration and deregistration of URI handlers
|
* registration and deregistration of URI handlers
|
||||||
*/
|
*/
|
||||||
@@ -168,15 +195,19 @@ esp_err_t ctrl_put_handler(httpd_req_t *req)
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (buf == '0') {
|
if (buf == '0') {
|
||||||
/* Handler can be unregistered using the uri string */
|
/* URI handlers can be unregistered using the uri string */
|
||||||
ESP_LOGI(TAG, "Unregistering /hello and /echo URIs");
|
ESP_LOGI(TAG, "Unregistering /hello and /echo URIs");
|
||||||
httpd_unregister_uri(req->handle, "/hello");
|
httpd_unregister_uri(req->handle, "/hello");
|
||||||
httpd_unregister_uri(req->handle, "/echo");
|
httpd_unregister_uri(req->handle, "/echo");
|
||||||
|
/* Register the custom error handler */
|
||||||
|
httpd_register_err_handler(req->handle, HTTPD_404_NOT_FOUND, http_404_error_handler);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
ESP_LOGI(TAG, "Registering /hello and /echo URIs");
|
ESP_LOGI(TAG, "Registering /hello and /echo URIs");
|
||||||
httpd_register_uri_handler(req->handle, &hello);
|
httpd_register_uri_handler(req->handle, &hello);
|
||||||
httpd_register_uri_handler(req->handle, &echo);
|
httpd_register_uri_handler(req->handle, &echo);
|
||||||
|
/* Unregister custom error handler */
|
||||||
|
httpd_register_err_handler(req->handle, HTTPD_404_NOT_FOUND, NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Respond with empty body */
|
/* Respond with empty body */
|
||||||
|
@@ -19,7 +19,20 @@ from __future__ import unicode_literals
|
|||||||
from builtins import str
|
from builtins import str
|
||||||
import http.client
|
import http.client
|
||||||
import argparse
|
import argparse
|
||||||
import Utility
|
|
||||||
|
try:
|
||||||
|
import Utility
|
||||||
|
except ImportError:
|
||||||
|
import sys
|
||||||
|
import os
|
||||||
|
|
||||||
|
# This environment variable is expected on the host machine
|
||||||
|
# > export TEST_FW_PATH=~/esp/esp-idf/tools/tiny-test-fw
|
||||||
|
test_fw_path = os.getenv("TEST_FW_PATH")
|
||||||
|
if test_fw_path and test_fw_path not in sys.path:
|
||||||
|
sys.path.insert(0, test_fw_path)
|
||||||
|
|
||||||
|
import Utility
|
||||||
|
|
||||||
|
|
||||||
def verbose_print(verbosity, *args):
|
def verbose_print(verbosity, *args):
|
||||||
@@ -27,6 +40,16 @@ def verbose_print(verbosity, *args):
|
|||||||
Utility.console_log(''.join(str(elems) for elems in args))
|
Utility.console_log(''.join(str(elems) for elems in args))
|
||||||
|
|
||||||
|
|
||||||
|
def test_val(text, expected, received):
|
||||||
|
if expected != received:
|
||||||
|
Utility.console_log(" Fail!")
|
||||||
|
Utility.console_log(" [reason] " + text + ":")
|
||||||
|
Utility.console_log(" expected: " + str(expected))
|
||||||
|
Utility.console_log(" received: " + str(received))
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def test_get_handler(ip, port, verbosity=False):
|
def test_get_handler(ip, port, verbosity=False):
|
||||||
verbose_print(verbosity, "======== GET HANDLER TEST =============")
|
verbose_print(verbosity, "======== GET HANDLER TEST =============")
|
||||||
# Establish HTTP connection
|
# Establish HTTP connection
|
||||||
@@ -44,12 +67,15 @@ def test_get_handler(ip, port, verbosity=False):
|
|||||||
resp = sess.getresponse()
|
resp = sess.getresponse()
|
||||||
resp_hdrs = resp.getheaders()
|
resp_hdrs = resp.getheaders()
|
||||||
resp_data = resp.read().decode()
|
resp_data = resp.read().decode()
|
||||||
try:
|
# Close HTTP connection
|
||||||
if resp.getheader("Custom-Header-1") != "Custom-Value-1":
|
sess.close()
|
||||||
return False
|
|
||||||
if resp.getheader("Custom-Header-2") != "Custom-Value-2":
|
if not (
|
||||||
return False
|
test_val("Status code mismatch", 200, resp.status) and
|
||||||
except Exception:
|
test_val("Response mismatch", "Custom-Value-1", resp.getheader("Custom-Header-1")) and
|
||||||
|
test_val("Response mismatch", "Custom-Value-2", resp.getheader("Custom-Header-2")) and
|
||||||
|
test_val("Response mismatch", "Hello World!", resp_data)
|
||||||
|
):
|
||||||
return False
|
return False
|
||||||
|
|
||||||
verbose_print(verbosity, "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv")
|
verbose_print(verbosity, "vvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvvv")
|
||||||
@@ -59,10 +85,7 @@ def test_get_handler(ip, port, verbosity=False):
|
|||||||
verbose_print(verbosity, "\t", k, ": ", v)
|
verbose_print(verbosity, "\t", k, ": ", v)
|
||||||
verbose_print(verbosity, "Response Data : " + resp_data)
|
verbose_print(verbosity, "Response Data : " + resp_data)
|
||||||
verbose_print(verbosity, "========================================\n")
|
verbose_print(verbosity, "========================================\n")
|
||||||
|
return True
|
||||||
# Close HTTP connection
|
|
||||||
sess.close()
|
|
||||||
return (resp_data == "Hello World!")
|
|
||||||
|
|
||||||
|
|
||||||
def test_post_handler(ip, port, msg, verbosity=False):
|
def test_post_handler(ip, port, msg, verbosity=False):
|
||||||
@@ -82,7 +105,7 @@ def test_post_handler(ip, port, msg, verbosity=False):
|
|||||||
|
|
||||||
# Close HTTP connection
|
# Close HTTP connection
|
||||||
sess.close()
|
sess.close()
|
||||||
return (resp_data == msg)
|
return test_val("Response mismatch", msg, resp_data)
|
||||||
|
|
||||||
|
|
||||||
def test_put_handler(ip, port, verbosity=False):
|
def test_put_handler(ip, port, verbosity=False):
|
||||||
@@ -91,31 +114,125 @@ def test_put_handler(ip, port, verbosity=False):
|
|||||||
verbose_print(verbosity, "Connecting to => " + ip + ":" + port)
|
verbose_print(verbosity, "Connecting to => " + ip + ":" + port)
|
||||||
sess = http.client.HTTPConnection(ip + ":" + port, timeout=15)
|
sess = http.client.HTTPConnection(ip + ":" + port, timeout=15)
|
||||||
|
|
||||||
# PUT message to /ctrl to disable /hello URI handler
|
# PUT message to /ctrl to disable /hello and /echo URI handlers
|
||||||
verbose_print(verbosity, "Disabling /hello handler")
|
# and set 404 error handler to custom http_404_error_handler()
|
||||||
|
verbose_print(verbosity, "Disabling /hello and /echo handlers")
|
||||||
sess.request("PUT", url="/ctrl", body="0")
|
sess.request("PUT", url="/ctrl", body="0")
|
||||||
resp = sess.getresponse()
|
resp = sess.getresponse()
|
||||||
resp.read()
|
resp.read()
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Send HTTP request to /hello URI
|
||||||
sess.request("GET", url="/hello")
|
sess.request("GET", url="/hello")
|
||||||
resp = sess.getresponse()
|
resp = sess.getresponse()
|
||||||
resp_data1 = resp.read().decode()
|
resp_data = resp.read().decode()
|
||||||
verbose_print(verbosity, "Response on GET /hello : " + resp_data1)
|
|
||||||
|
# 404 Error must be returned from server as URI /hello is no longer available.
|
||||||
|
# But the custom error handler http_404_error_handler() will not close the
|
||||||
|
# session if the requested URI is /hello
|
||||||
|
if not test_val("Status code mismatch", 404, resp.status):
|
||||||
|
raise AssertionError
|
||||||
|
|
||||||
|
# Compare error response string with expectation
|
||||||
|
verbose_print(verbosity, "Response on GET /hello : " + resp_data)
|
||||||
|
if not test_val("Response mismatch", "/hello URI is not available", resp_data):
|
||||||
|
raise AssertionError
|
||||||
|
|
||||||
|
# Using same session for sending an HTTP request to /echo, as it is expected
|
||||||
|
# that the custom error handler http_404_error_handler() would not have closed
|
||||||
|
# the session
|
||||||
|
sess.request("POST", url="/echo", body="Some content")
|
||||||
|
resp = sess.getresponse()
|
||||||
|
resp_data = resp.read().decode()
|
||||||
|
|
||||||
|
# 404 Error must be returned from server as URI /hello is no longer available.
|
||||||
|
# The custom error handler http_404_error_handler() will close the session
|
||||||
|
# this time as the requested URI is /echo
|
||||||
|
if not test_val("Status code mismatch", 404, resp.status):
|
||||||
|
raise AssertionError
|
||||||
|
|
||||||
|
# Compare error response string with expectation
|
||||||
|
verbose_print(verbosity, "Response on POST /echo : " + resp_data)
|
||||||
|
if not test_val("Response mismatch", "/echo URI is not available", resp_data):
|
||||||
|
raise AssertionError
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Using same session should fail as by now the session would have closed
|
||||||
|
sess.request("POST", url="/hello", body="Some content")
|
||||||
|
resp = sess.getresponse()
|
||||||
|
resp.read().decode()
|
||||||
|
|
||||||
|
# If control reaches this point then the socket was not closed.
|
||||||
|
# This is not expected
|
||||||
|
verbose_print(verbosity, "Socket not closed by server")
|
||||||
|
raise AssertionError
|
||||||
|
|
||||||
|
except http.client.HTTPException:
|
||||||
|
# Catch socket error as we tried to communicate with an already closed socket
|
||||||
|
pass
|
||||||
|
|
||||||
|
except http.client.HTTPException:
|
||||||
|
verbose_print(verbosity, "Socket closed by server")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except AssertionError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
finally:
|
||||||
|
# Close HTTP connection
|
||||||
|
sess.close()
|
||||||
|
|
||||||
# PUT message to /ctrl to enable /hello URI handler
|
|
||||||
verbose_print(verbosity, "Enabling /hello handler")
|
verbose_print(verbosity, "Enabling /hello handler")
|
||||||
|
# Create new connection
|
||||||
|
sess = http.client.HTTPConnection(ip + ":" + port, timeout=15)
|
||||||
|
# PUT message to /ctrl to enable /hello URI handler
|
||||||
|
# and restore 404 error handler to default
|
||||||
sess.request("PUT", url="/ctrl", body="1")
|
sess.request("PUT", url="/ctrl", body="1")
|
||||||
resp = sess.getresponse()
|
resp = sess.getresponse()
|
||||||
resp.read()
|
resp.read()
|
||||||
|
|
||||||
sess.request("GET", url="/hello")
|
|
||||||
resp = sess.getresponse()
|
|
||||||
resp_data2 = resp.read().decode()
|
|
||||||
verbose_print(verbosity, "Response on GET /hello : " + resp_data2)
|
|
||||||
|
|
||||||
# Close HTTP connection
|
# Close HTTP connection
|
||||||
sess.close()
|
sess.close()
|
||||||
return ((resp_data2 == "Hello World!") and (resp_data1 == "This URI doesn't exist"))
|
|
||||||
|
# Create new connection
|
||||||
|
sess = http.client.HTTPConnection(ip + ":" + port, timeout=15)
|
||||||
|
|
||||||
|
try:
|
||||||
|
# Sending HTTP request to /hello should work now
|
||||||
|
sess.request("GET", url="/hello")
|
||||||
|
resp = sess.getresponse()
|
||||||
|
resp_data = resp.read().decode()
|
||||||
|
|
||||||
|
if not test_val("Status code mismatch", 200, resp.status):
|
||||||
|
raise AssertionError
|
||||||
|
|
||||||
|
verbose_print(verbosity, "Response on GET /hello : " + resp_data)
|
||||||
|
if not test_val("Response mismatch", "Hello World!", resp_data):
|
||||||
|
raise AssertionError
|
||||||
|
|
||||||
|
# 404 Error handler should have been restored to default
|
||||||
|
sess.request("GET", url="/invalid")
|
||||||
|
resp = sess.getresponse()
|
||||||
|
resp_data = resp.read().decode()
|
||||||
|
|
||||||
|
if not test_val("Status code mismatch", 404, resp.status):
|
||||||
|
raise AssertionError
|
||||||
|
|
||||||
|
verbose_print(verbosity, "Response on GET /invalid : " + resp_data)
|
||||||
|
if not test_val("Response mismatch", "This URI does not exist", resp_data):
|
||||||
|
raise AssertionError
|
||||||
|
|
||||||
|
except http.client.HTTPException:
|
||||||
|
verbose_print(verbosity, "Socket closed by server")
|
||||||
|
return False
|
||||||
|
|
||||||
|
except AssertionError:
|
||||||
|
return False
|
||||||
|
|
||||||
|
finally:
|
||||||
|
# Close HTTP connection
|
||||||
|
sess.close()
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
def test_custom_uri_query(ip, port, query, verbosity=False):
|
def test_custom_uri_query(ip, port, query, verbosity=False):
|
||||||
@@ -138,7 +255,7 @@ def test_custom_uri_query(ip, port, query, verbosity=False):
|
|||||||
|
|
||||||
# Close HTTP connection
|
# Close HTTP connection
|
||||||
sess.close()
|
sess.close()
|
||||||
return (resp_data == "Hello World!")
|
return "Hello World!" == resp_data
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
@@ -154,9 +271,9 @@ if __name__ == '__main__':
|
|||||||
port = args['port']
|
port = args['port']
|
||||||
msg = args['msg']
|
msg = args['msg']
|
||||||
|
|
||||||
if not test_get_handler(ip, port, True):
|
if not (
|
||||||
Utility.console_log("Failed!")
|
test_get_handler(ip, port, True) and
|
||||||
if not test_post_handler(ip, port, msg, True):
|
test_put_handler(ip, port, True) and
|
||||||
Utility.console_log("Failed!")
|
test_post_handler(ip, port, msg, True)
|
||||||
if not test_put_handler(ip, port, True):
|
):
|
||||||
Utility.console_log("Failed!")
|
Utility.console_log("Failed!")
|
||||||
|
Reference in New Issue
Block a user