Repository navigation
Improve remote shell loop error handling #851
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Changes from all commits
bfe6ffb
0b909e6
dd06cb4
885c8e4
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -31,6 +31,11 @@ | |
|
|
||
| #include "celix_compiler.h" | ||
| #include "celix_threads.h" | ||
| #include "celix_stdlib_cleanup.h" | ||
|
|
||
| #define CELIX_HTTP_ADMIN_READ_ERROR_MSG "Bad Request: Read error" | ||
| #define CELIX_HTTP_ADMIN_INCOMPLETE_BODY_MSG "Bad Request: Incomplete Body" | ||
| #define CELIX_HTTP_ADMIN_INSUFFICIENT_MEM_MSG "Server Error: Insufficient memory" | ||
|
|
||
|
|
||
| struct http_admin_manager { | ||
|
|
@@ -56,6 +61,11 @@ typedef struct http_alias { | |
|
|
||
| //Local function prototypes | ||
| static int http_request_handle(struct mg_connection *connection); | ||
| /** | ||
| * @brief read the request body. | ||
| * @return 0 if succesfull, > 0 and a error code (4xx or 5xx) if not sucessfull. | ||
| */ | ||
| static int httpAdmin_readRequestBody(struct mg_connection *connection, long long content_length, char **bufferOut, size_t *bytesReadOut, const char** errorMsgOut); | ||
| static void httpAdmin_updateInfoSvc(http_admin_manager_t *admin); | ||
| static void createAliasesSymlink(const char *aliases, const char *admin_root, const char *bundle_root, long bundle_id, celix_array_list_t *alias_list); | ||
| static bool aliasList_containsAlias(celix_array_list_t *alias_list, const char *alias); | ||
|
|
@@ -173,6 +183,39 @@ void http_admin_removeHttpService(void *handle, void *svc CELIX_UNUSED, const ce | |
| } | ||
| } | ||
|
|
||
| static int httpAdmin_readRequestBody(struct mg_connection* connection, long long contentLength, char** bufferOut, size_t* bytesReadOut, const char** errorMsgOut) { | ||
| celix_autofree char* buffer = NULL; | ||
| size_t totalBytesRead = 0; | ||
| *errorMsgOut = NULL; | ||
| if (contentLength > 0) { | ||
| size_t length = (contentLength > INT_MAX) ? INT_MAX : (size_t)contentLength; | ||
| buffer = malloc(length + 1); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Shall we apply some upper bound to request body size? Or we may explicitly refuse requests without content-length by returning |
||
| if (buffer == NULL) { | ||
| *errorMsgOut = CELIX_HTTP_ADMIN_INSUFFICIENT_MEM_MSG; | ||
| return 500; | ||
| } | ||
|
|
||
| while (totalBytesRead < length) { | ||
| int read = mg_read(connection, buffer + totalBytesRead, length - totalBytesRead); | ||
| if (read == 0) { | ||
| break; //EOF | ||
| } else if (read < 0) { | ||
| *errorMsgOut = CELIX_HTTP_ADMIN_READ_ERROR_MSG; | ||
| return 400; | ||
| } | ||
| totalBytesRead += (size_t)read; | ||
| } | ||
| if (totalBytesRead < length) { | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. What if |
||
| *errorMsgOut = CELIX_HTTP_ADMIN_INCOMPLETE_BODY_MSG; | ||
| return 400; | ||
| } | ||
| buffer[totalBytesRead] = '\0'; | ||
| } | ||
| *bufferOut = celix_steal_ptr(buffer); | ||
| *bytesReadOut = totalBytesRead; | ||
| return 0; | ||
| } | ||
|
|
||
| int http_request_handle(struct mg_connection *connection) { | ||
| int ret_status = 400; //Default bad request | ||
|
|
||
|
|
@@ -208,59 +251,34 @@ int http_request_handle(struct mg_connection *connection) { | |
| } | ||
| } else if (strcmp("POST", ri->request_method) == 0) { | ||
| if (httpSvc->doPost != NULL) { | ||
| int bytes_read = 0; | ||
| bool no_data = false; | ||
| char *rcv_buf = NULL; | ||
|
|
||
| if (ri->content_length > 0) { | ||
| int content_size = (ri->content_length > INT_MAX ? INT_MAX : (int) ri->content_length); | ||
| rcv_buf = malloc((size_t) content_size + 1); | ||
| rcv_buf[content_size] = '\0'; | ||
| bytes_read = mg_read(connection, rcv_buf, (size_t) content_size); | ||
| size_t bytesRead = 0; | ||
| const char* errMsg; | ||
| int errCode = httpAdmin_readRequestBody(connection, ri->content_length, &rcv_buf, &bytesRead, &errMsg); | ||
| if (errCode == 0) { | ||
| ret_status = httpSvc->doPost(httpSvc->handle, connection, rcv_buf, bytesRead); | ||
| } else { | ||
| no_data = true; | ||
| } | ||
|
|
||
| if (bytes_read > 0 || no_data) { | ||
| ret_status = httpSvc->doPost(httpSvc->handle, connection, rcv_buf, (size_t) bytes_read); | ||
| } else { | ||
| mg_send_http_error(connection, 400, "%s", "Bad request"); | ||
| ret_status = 400; //Bad Request, failed to read data | ||
| } | ||
|
|
||
| if (rcv_buf != NULL) { | ||
| free(rcv_buf); | ||
| mg_send_http_error(connection, errCode, "%s", errMsg); | ||
| ret_status = errCode; //set status to the error code, so the request is not passed to civetweb | ||
| } | ||
| free(rcv_buf); | ||
| } else { | ||
| ret_status = 0; //Let civetweb handle the request | ||
| } | ||
|
|
||
| } else if (strcmp("PUT", ri->request_method) == 0) { | ||
| if (httpSvc->doPut != NULL) { | ||
| int bytes_read = 0; | ||
| bool no_data = false; | ||
| char *rcv_buf = NULL; | ||
|
|
||
| if (ri->content_length > 0) { | ||
| int content_size = (ri->content_length > INT_MAX ? INT_MAX : (int) ri->content_length); | ||
| rcv_buf = malloc((size_t) content_size + 1); | ||
| rcv_buf[content_size] = '\0'; | ||
| bytes_read = mg_read(connection, rcv_buf, (size_t) content_size); | ||
| size_t bytesRead = 0; | ||
| const char* errMsg; | ||
| int errCode = httpAdmin_readRequestBody(connection, ri->content_length, &rcv_buf, &bytesRead, &errMsg); | ||
| if (errCode == 0) { | ||
| ret_status = httpSvc->doPut(httpSvc->handle, connection, req_uri, rcv_buf, bytesRead); | ||
| } else { | ||
| no_data = true; | ||
| } | ||
|
|
||
| if (bytes_read > 0 || no_data) { | ||
| ret_status = httpSvc->doPut(httpSvc->handle, connection, req_uri, rcv_buf, | ||
| (size_t) bytes_read); | ||
| } else { | ||
| mg_send_http_error(connection, 400, "%s", "Bad request"); | ||
| ret_status = 400; //Bad Request, failed to read data | ||
| } | ||
|
|
||
| if (rcv_buf != NULL) { | ||
| free(rcv_buf); | ||
| mg_send_http_error(connection, errCode, "%s", errMsg); | ||
| ret_status = errCode; //set status to the error code, so the request is not passed to civetweb | ||
| } | ||
| free(rcv_buf); | ||
| } else { | ||
| ret_status = 0; //Let civetweb handle the request | ||
| } | ||
|
|
@@ -272,29 +290,17 @@ int http_request_handle(struct mg_connection *connection) { | |
| } | ||
| } else if (strcmp("TRACE", ri->request_method) == 0) { | ||
| if (httpSvc->doTrace != NULL) { | ||
| int bytes_read = 0; | ||
| bool no_data = false; | ||
| char *rcv_buf = NULL; | ||
|
|
||
| if (ri->content_length > 0) { | ||
| int content_size = (ri->content_length > INT_MAX ? INT_MAX : (int) ri->content_length); | ||
| rcv_buf = malloc((size_t) content_size + 1); | ||
| rcv_buf[content_size] = '\0'; | ||
| bytes_read = mg_read(connection, rcv_buf, (size_t) content_size); | ||
| } else { | ||
| no_data = true; | ||
| } | ||
|
|
||
| if (bytes_read > 0 || no_data) { | ||
| ret_status = httpSvc->doTrace(httpSvc->handle, connection, rcv_buf, (size_t) bytes_read); | ||
| size_t bytesRead = 0; | ||
| const char* errMsg = NULL; | ||
| int errCode = httpAdmin_readRequestBody(connection, ri->content_length, &rcv_buf, &bytesRead, &errMsg); | ||
| if (errCode == 0) { | ||
| ret_status = httpSvc->doTrace(httpSvc->handle, connection, rcv_buf, bytesRead); | ||
| } else { | ||
| mg_send_http_error(connection, 400, "%s", "Bad request"); | ||
| ret_status = 400; //Bad Request, failed to read data | ||
| } | ||
|
|
||
| if (rcv_buf != NULL) { | ||
| free(rcv_buf); | ||
| mg_send_http_error(connection, errCode, "%s", errMsg); | ||
| ret_status = errCode; //set status to the error code, so the request is not passed to civetweb | ||
| } | ||
| free(rcv_buf); | ||
| } else { | ||
| ret_status = 0; //Let civetweb handle the request | ||
| } | ||
|
|
@@ -306,30 +312,17 @@ int http_request_handle(struct mg_connection *connection) { | |
| } | ||
| } else if (strcmp("PATCH", ri->request_method) == 0) { | ||
| if (httpSvc->doPatch != NULL) { | ||
| int bytes_read = 0; | ||
| bool no_data = false; | ||
| char *rcv_buf = NULL; | ||
|
|
||
| if (ri->content_length > 0) { | ||
| int content_size = (ri->content_length > INT_MAX ? INT_MAX : (int) ri->content_length); | ||
| rcv_buf = malloc((size_t) content_size + 1); | ||
| rcv_buf[content_size] = '\0'; | ||
| bytes_read = mg_read(connection, rcv_buf, (size_t) content_size); | ||
| } else { | ||
| no_data = true; | ||
| } | ||
|
|
||
| if (bytes_read > 0 || no_data) { | ||
| ret_status = httpSvc->doPatch(httpSvc->handle, connection, req_uri, rcv_buf, | ||
| (size_t) bytes_read); | ||
| size_t bytesRead = 0; | ||
| const char* errMsg; | ||
| int errCode = httpAdmin_readRequestBody(connection, ri->content_length, &rcv_buf, &bytesRead, &errMsg); | ||
| if (errCode == 0) { | ||
| ret_status = httpSvc->doPatch(httpSvc->handle, connection, req_uri, rcv_buf, bytesRead); | ||
| } else { | ||
| mg_send_http_error(connection, 400, "%s", "Bad request"); | ||
| ret_status = 400; //Bad Request, failed to read data | ||
| } | ||
|
|
||
| if (rcv_buf != NULL) { | ||
| free(rcv_buf); | ||
| mg_send_http_error(connection, errCode, "%s", errMsg); | ||
| ret_status = errCode; //set status to the error code, so the request is not passed to civetweb | ||
| } | ||
| free(rcv_buf); | ||
| } else { | ||
| ret_status = 0; //Let civetweb handle the request | ||
| } | ||
|
|
||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The status texts like "Bad Request"/"server Error" are redundent according to
mg_send_http_errordocumentation:Check https://github.com/civetweb/civetweb/blob/588860e30721bf5453b0440c390865a8e85dcae5/examples/rest/rest.c#L94 for example usage.