Repository navigation
Conversation
Codecov Report❌ Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #851 +/- ##
========================================
Coverage 91.54% 91.55%
========================================
Files 235 235
Lines 28787 28961 +174
========================================
+ Hits 26353 26514 +161
- Misses 2434 2447 +13 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
PengZheng
left a comment
There was a problem hiding this comment.
Nice improvement for our networking code.
The HTTP code is good enough except for its zero return handling.
The TCP part is more difficult to deal with raw socket API.
| } else { //error | ||
| remoteShell_connection_print(connection, RS_ERROR); | ||
| remoteShell_connection_print(connection, RS_PROMPT); | ||
| len = recv(fd, buff + used, COMMAND_BUFF_SIZE - 1 - used, 0); |
There was a problem hiding this comment.
This is still not robust enough. A common error breaking this is EINTR, which requires retry.
Note EINTR is not the only such status code, EAGAIN/EWOULDBLOCK to name a few.
We also need to take platform difference (macOS and Linux) into account.
There was a problem hiding this comment.
done, also added a specific function to check EAGAIN/EWOULDBLOCK, so that we can make this platform dependent in a cohesive way.
There was a problem hiding this comment.
This applies to sockets in non-blocking mode.
I have not checked whether sockets in remote_shell has been set in this mode.
PengZheng
left a comment
There was a problem hiding this comment.
I left some further remarks, some of which need to be addressed before merging this PR.
| } | ||
| totalBytesRead += (size_t)read; | ||
| } | ||
| if (totalBytesRead < length) { |
There was a problem hiding this comment.
What if contentLength == -1? Then we can never receive a request without explicit content_length successfully.
| *errorMsgOut = NULL; | ||
| if (contentLength > 0) { | ||
| size_t length = (contentLength > INT_MAX) ? INT_MAX : (size_t)contentLength; | ||
| buffer = malloc(length + 1); |
There was a problem hiding this comment.
Shall we apply some upper bound to request body size?
For a request without explicit content-length (Transfer-Encoding: chunked), it is not safe to allocate so much memory.
And it would be nice to have test cases for both such unusually large requests and reqeusts with chunked transfer-encoding.
Or we may explicitly refuse requests without content-length by returning 411 (Length Required).
This way we cannot process chunked requests.
|
|
||
| #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" |
There was a problem hiding this comment.
The status texts like "Bad Request"/"server Error" are redundent according to mg_send_http_error documentation:
The status text (e.g., "Not Found") for standard error codes is known by this function. A body of the error message, to explain the error in more detail, can be specified using the fmt format specifier and additional arguments. The fmt format specifier works like for the printf() function in the standard C library.
Check https://github.com/civetweb/civetweb/blob/588860e30721bf5453b0440c390865a8e85dcae5/examples/rest/rest.c#L94 for example usage.
| } | ||
| if (contentLength > 0 && (unsigned long long)contentLength > maxRequestBodySize) { | ||
| RSA_LOG_ERROR(rsa, "Error while reading request body, the body is larger than the maximum of %zu bytes", maxRequestBodySize); | ||
| mg_send_http_error(conn, 413, "%s", "Request body too large"); |
There was a problem hiding this comment.
As already mentioned, mg_send_http_error will add status text corresponding to error code, as in https://github.com/civetweb/civetweb/blob/588860e30721bf5453b0440c390865a8e85dcae5/src/civetweb.c#L4677
This remark applies to all usages of this API.
| if (rc != CELIX_SUCCESS) { | ||
| RSA_LOG_ERROR(rsa, "Error trying to invoke remove service, got error %i\n", rc); | ||
| } | ||
| if (contentLength > 0 && (unsigned long long)contentLength > maxRequestBodySize) { |
There was a problem hiding this comment.
Note that 0 is a valid Content-Length value, which just means message body is empty.
This is invalid for the remote service scenario, and thus we can avoid the following memory allocation and return error early.
| RSA_LOG_ERROR(rsa, "Error trying to invoke remove service, got error %i\n", rc); | ||
| mg_send_http_error(conn, 500, "%s", "Internal server error"); | ||
| } else if (response != NULL) { | ||
| mg_write(conn, data_response_headers, strlen(data_response_headers)); |
There was a problem hiding this comment.
It does not make sense to send data_response_headers and response differently.
The return value of the former send is not checked at all.
| break; | ||
| } | ||
| } | ||
| if (contentLength <= 0 && readLen > maxRequestBodySize) { |
There was a problem hiding this comment.
contentLength == 0 is invalid for our use case.
| for (i = 0; i < length; i += 1) { | ||
| connection_pt connection = celix_arrayList_get(instance->connections, i); | ||
| connection->threadRunning = false; | ||
| connection_setThreadRunning(connection, false); |
There was a problem hiding this comment.
I have found no synchronization between connection processing thread and the calling thread, and thus suspect use-after-free bugs here.
Moreover, we never calling pthread_join on these connection processing thread, these are definitely resource leaks.
| } while (result == -1 && errno == EINTR && connection_isThreadRunning(connection)); | ||
|
|
||
| /* The socket_fd has data available to be read */ | ||
| if (result > 0 && FD_ISSET(fd, &connection->pollset)) { |
There was a problem hiding this comment.
What if result == -1 with a non-trivial errno? Should we quit?
| } else { //error | ||
| remoteShell_connection_print(connection, RS_ERROR); | ||
| remoteShell_connection_print(connection, RS_PROMPT); | ||
| len = recv(fd, buff + used, COMMAND_BUFF_SIZE - 1 - used, 0); |
There was a problem hiding this comment.
This applies to sockets in non-blocking mode.
I have not checked whether sockets in remote_shell has been set in this mode.
Improve remote shell loop by
recvreturn and then logging result and exiting loop if needed.