]> granicus.if.org Git - esp-idf/blobdiff - components/http_server/src/httpd_txrx.c
HTTP Server : Bug fixed in httpd_recv logic and updated function descriptions
[esp-idf] / components / http_server / src / httpd_txrx.c
index 5cf95b351d82d498223f81e617c8700f6cadee82..ed90cb75da17d7fa112abbe0e2f07b1f42d484c8 100644 (file)
@@ -55,18 +55,18 @@ esp_err_t httpd_set_recv_override(httpd_req_t *r, httpd_recv_func_t recv_func)
 int httpd_send(httpd_req_t *r, const char *buf, size_t buf_len)
 {
     if (r == NULL || buf == NULL) {
-        return -1;
+        return HTTPD_SOCK_ERR_INVALID;
     }
 
     if (!httpd_valid_req(r)) {
-        return -1;
+        return HTTPD_SOCK_ERR_INVALID;
     }
 
     struct httpd_req_aux *ra = r->aux;
     int ret = ra->sd->send_fn(ra->sd->fd, buf, buf_len, 0);
     if (ret < 0) {
         ESP_LOGD(TAG, LOG_FMT("error in send_fn"));
-        return -1;
+        return ret;
     }
     return ret;
 }
@@ -128,7 +128,16 @@ int httpd_recv_with_opt(httpd_req_t *r, char *buf, size_t buf_len, bool halt_aft
     int ret = ra->sd->recv_fn(ra->sd->fd, buf, buf_len, 0);
     if (ret < 0) {
         ESP_LOGD(TAG, LOG_FMT("error in recv_fn"));
-        return -1;
+        if ((ret == HTTPD_SOCK_ERR_TIMEOUT) && (pending_len != 0)) {
+            /* If recv() timeout occurred, but pending data is
+             * present, return length of pending data.
+             * This behavior is similar to that of socket recv()
+             * function, which, in case has only partially read the
+             * requested length, due to timeout, returns with read
+             * length, rather than error */
+            return pending_len;
+        }
+        return ret;
     }
 
     ESP_LOGD(TAG, LOG_FMT("received length = %d"), ret + pending_len);
@@ -429,12 +438,12 @@ esp_err_t httpd_resp_send_err(httpd_req_t *req, httpd_err_resp_t error)
 int httpd_req_recv(httpd_req_t *r, char *buf, size_t buf_len)
 {
     if (r == NULL || buf == NULL) {
-        return -1;
+        return HTTPD_SOCK_ERR_INVALID;
     }
 
     if (!httpd_valid_req(r)) {
         ESP_LOGW(TAG, LOG_FMT("invalid request"));
-        return -1;
+        return HTTPD_SOCK_ERR_INVALID;
     }
 
     struct httpd_req_aux *ra = r->aux;
@@ -450,8 +459,7 @@ int httpd_req_recv(httpd_req_t *r, char *buf, size_t buf_len)
     int ret = httpd_recv(r, buf, buf_len);
     if (ret < 0) {
         ESP_LOGD(TAG, LOG_FMT("error in httpd_recv"));
-        ra->remaining_len = 0;
-        return -1;
+        return ret;
     }
     ra->remaining_len -= ret;
     ESP_LOGD(TAG, LOG_FMT("received length = %d"), ret);
@@ -473,15 +481,44 @@ int httpd_req_to_sockfd(httpd_req_t *r)
     return ra->sd->fd;
 }
 
+static int httpd_sock_err(const char *ctx, int sockfd)
+{
+    int errval;
+    int sock_err;
+    size_t sock_err_len = sizeof(sock_err);
+
+    if (getsockopt(sockfd, SOL_SOCKET, SO_ERROR, &sock_err, &sock_err_len) < 0) {
+        ESP_LOGE(TAG, LOG_FMT("error calling getsockopt : %d"), errno);
+        return HTTPD_SOCK_ERR_FAIL;
+    }
+    ESP_LOGW(TAG, LOG_FMT("error in %s : %d"), ctx, sock_err);
+
+    switch(sock_err) {
+    case EAGAIN:
+    case EINTR:
+        errval = HTTPD_SOCK_ERR_TIMEOUT;
+        break;
+    case EINVAL:
+    case EBADF:
+    case EFAULT:
+    case ENOTSOCK:
+        errval = HTTPD_SOCK_ERR_INVALID;
+        break;
+    default:
+        errval = HTTPD_SOCK_ERR_FAIL;
+    }
+    return errval;
+}
+
 int httpd_default_send(int sockfd, const char *buf, size_t buf_len, int flags)
 {
     if (buf == NULL) {
-        return ESP_ERR_INVALID_ARG;
+        return HTTPD_SOCK_ERR_INVALID;
     }
 
     int ret = send(sockfd, buf, buf_len, flags);
     if (ret < 0) {
-        ESP_LOGW(TAG, LOG_FMT("error in send = %d"), errno);
+        return httpd_sock_err("send", sockfd);
     }
     return ret;
 }
@@ -489,12 +526,12 @@ int httpd_default_send(int sockfd, const char *buf, size_t buf_len, int flags)
 int httpd_default_recv(int sockfd, char *buf, size_t buf_len, int flags)
 {
     if (buf == NULL) {
-        return ESP_ERR_INVALID_ARG;
+        return HTTPD_SOCK_ERR_INVALID;
     }
 
     int ret = recv(sockfd, buf, buf_len, flags);
     if (ret < 0) {
-        ESP_LOGW(TAG, LOG_FMT("error in recv = %d"), errno);
+        return httpd_sock_err("recv", sockfd);
     }
     return ret;
 }