1 // Copyright 2018 Espressif Systems (Shanghai) PTE LTD
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 //     http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 
15 
16 #include <errno.h>
17 #include <esp_log.h>
18 #include <esp_err.h>
19 
20 #include <esp_http_server.h>
21 #include "esp_httpd_priv.h"
22 
23 static const char *TAG = "httpd_txrx";
24 
httpd_sess_set_send_override(httpd_handle_t hd,int sockfd,httpd_send_func_t send_func)25 esp_err_t httpd_sess_set_send_override(httpd_handle_t hd, int sockfd, httpd_send_func_t send_func)
26 {
27     struct sock_db *sess = httpd_sess_get(hd, sockfd);
28     if (!sess) {
29         return ESP_ERR_INVALID_ARG;
30     }
31     sess->send_fn = send_func;
32     return ESP_OK;
33 }
34 
httpd_sess_set_recv_override(httpd_handle_t hd,int sockfd,httpd_recv_func_t recv_func)35 esp_err_t httpd_sess_set_recv_override(httpd_handle_t hd, int sockfd, httpd_recv_func_t recv_func)
36 {
37     struct sock_db *sess = httpd_sess_get(hd, sockfd);
38     if (!sess) {
39         return ESP_ERR_INVALID_ARG;
40     }
41     sess->recv_fn = recv_func;
42     return ESP_OK;
43 }
44 
httpd_sess_set_pending_override(httpd_handle_t hd,int sockfd,httpd_pending_func_t pending_func)45 esp_err_t httpd_sess_set_pending_override(httpd_handle_t hd, int sockfd, httpd_pending_func_t pending_func)
46 {
47     struct sock_db *sess = httpd_sess_get(hd, sockfd);
48     if (!sess) {
49         return ESP_ERR_INVALID_ARG;
50     }
51     sess->pending_fn = pending_func;
52     return ESP_OK;
53 }
54 
httpd_send(httpd_req_t * r,const char * buf,size_t buf_len)55 int httpd_send(httpd_req_t *r, const char *buf, size_t buf_len)
56 {
57     if (r == NULL || buf == NULL) {
58         return HTTPD_SOCK_ERR_INVALID;
59     }
60 
61     if (!httpd_valid_req(r)) {
62         return HTTPD_SOCK_ERR_INVALID;
63     }
64 
65     struct httpd_req_aux *ra = r->aux;
66     int ret = ra->sd->send_fn(ra->sd->handle, ra->sd->fd, buf, buf_len, 0);
67     if (ret < 0) {
68         ESP_LOGD(TAG, LOG_FMT("error in send_fn"));
69         return ret;
70     }
71     return ret;
72 }
73 
httpd_send_all(httpd_req_t * r,const char * buf,size_t buf_len)74 static esp_err_t httpd_send_all(httpd_req_t *r, const char *buf, size_t buf_len)
75 {
76     struct httpd_req_aux *ra = r->aux;
77     int ret;
78 
79     while (buf_len > 0) {
80         ret = ra->sd->send_fn(ra->sd->handle, ra->sd->fd, buf, buf_len, 0);
81         if (ret < 0) {
82             ESP_LOGD(TAG, LOG_FMT("error in send_fn"));
83             return ESP_FAIL;
84         }
85         ESP_LOGD(TAG, LOG_FMT("sent = %d"), ret);
86         buf     += ret;
87         buf_len -= ret;
88     }
89     return ESP_OK;
90 }
91 
httpd_recv_pending(httpd_req_t * r,char * buf,size_t buf_len)92 static size_t httpd_recv_pending(httpd_req_t *r, char *buf, size_t buf_len)
93 {
94     struct httpd_req_aux *ra = r->aux;
95     size_t offset = sizeof(ra->sd->pending_data) - ra->sd->pending_len;
96 
97     /* buf_len must not be greater than remaining_len */
98     buf_len = MIN(ra->sd->pending_len, buf_len);
99     memcpy(buf, ra->sd->pending_data + offset, buf_len);
100 
101     ra->sd->pending_len -= buf_len;
102     return buf_len;
103 }
104 
httpd_recv_with_opt(httpd_req_t * r,char * buf,size_t buf_len,bool halt_after_pending)105 int httpd_recv_with_opt(httpd_req_t *r, char *buf, size_t buf_len, bool halt_after_pending)
106 {
107     ESP_LOGD(TAG, LOG_FMT("requested length = %d"), buf_len);
108 
109     size_t pending_len = 0;
110     struct httpd_req_aux *ra = r->aux;
111 
112     /* First fetch pending data from local buffer */
113     if (ra->sd->pending_len > 0) {
114         ESP_LOGD(TAG, LOG_FMT("pending length = %d"), ra->sd->pending_len);
115         pending_len = httpd_recv_pending(r, buf, buf_len);
116         buf     += pending_len;
117         buf_len -= pending_len;
118 
119         /* If buffer filled then no need to recv.
120          * If asked to halt after receiving pending data then
121          * return with received length */
122         if (!buf_len || halt_after_pending) {
123             return pending_len;
124         }
125     }
126 
127     /* Receive data of remaining length */
128     int ret = ra->sd->recv_fn(ra->sd->handle, ra->sd->fd, buf, buf_len, 0);
129     if (ret < 0) {
130         ESP_LOGD(TAG, LOG_FMT("error in recv_fn"));
131         if ((ret == HTTPD_SOCK_ERR_TIMEOUT) && (pending_len != 0)) {
132             /* If recv() timeout occurred, but pending data is
133              * present, return length of pending data.
134              * This behavior is similar to that of socket recv()
135              * function, which, in case has only partially read the
136              * requested length, due to timeout, returns with read
137              * length, rather than error */
138             return pending_len;
139         }
140         return ret;
141     }
142 
143     ESP_LOGD(TAG, LOG_FMT("received length = %d"), ret + pending_len);
144     return ret + pending_len;
145 }
146 
httpd_recv(httpd_req_t * r,char * buf,size_t buf_len)147 int httpd_recv(httpd_req_t *r, char *buf, size_t buf_len)
148 {
149     return httpd_recv_with_opt(r, buf, buf_len, false);
150 }
151 
httpd_unrecv(struct httpd_req * r,const char * buf,size_t buf_len)152 size_t httpd_unrecv(struct httpd_req *r, const char *buf, size_t buf_len)
153 {
154     struct httpd_req_aux *ra = r->aux;
155     /* Truncate if external buf_len is greater than pending_data buffer size */
156     ra->sd->pending_len = MIN(sizeof(ra->sd->pending_data), buf_len);
157 
158     /* Copy data into internal pending_data buffer with the exact offset
159      * such that it is right aligned inside the buffer */
160     size_t offset = sizeof(ra->sd->pending_data) - ra->sd->pending_len;
161     memcpy(ra->sd->pending_data + offset, buf, ra->sd->pending_len);
162     ESP_LOGD(TAG, LOG_FMT("length = %d"), ra->sd->pending_len);
163     return ra->sd->pending_len;
164 }
165 
166 /**
167  * This API appends an additional header field-value pair in the HTTP response.
168  * But the header isn't sent out until any of the send APIs is executed.
169  */
httpd_resp_set_hdr(httpd_req_t * r,const char * field,const char * value)170 esp_err_t httpd_resp_set_hdr(httpd_req_t *r, const char *field, const char *value)
171 {
172     if (r == NULL || field == NULL || value == NULL) {
173         return ESP_ERR_INVALID_ARG;
174     }
175 
176     if (!httpd_valid_req(r)) {
177         return ESP_ERR_HTTPD_INVALID_REQ;
178     }
179 
180     struct httpd_req_aux *ra = r->aux;
181     struct httpd_data *hd = (struct httpd_data *) r->handle;
182 
183     /* Number of additional headers is limited */
184     if (ra->resp_hdrs_count >= hd->config.max_resp_headers) {
185         return ESP_ERR_HTTPD_RESP_HDR;
186     }
187 
188     /* Assign header field-value pair */
189     ra->resp_hdrs[ra->resp_hdrs_count].field = field;
190     ra->resp_hdrs[ra->resp_hdrs_count].value = value;
191     ra->resp_hdrs_count++;
192 
193     ESP_LOGD(TAG, LOG_FMT("new header = %s: %s"), field, value);
194     return ESP_OK;
195 }
196 
197 /**
198  * This API sets the status of the HTTP response to the value specified.
199  * But the status isn't sent out until any of the send APIs is executed.
200  */
httpd_resp_set_status(httpd_req_t * r,const char * status)201 esp_err_t httpd_resp_set_status(httpd_req_t *r, const char *status)
202 {
203     if (r == NULL || status == NULL) {
204         return ESP_ERR_INVALID_ARG;
205     }
206 
207     if (!httpd_valid_req(r)) {
208         return ESP_ERR_HTTPD_INVALID_REQ;
209     }
210 
211     struct httpd_req_aux *ra = r->aux;
212     ra->status = (char *)status;
213     return ESP_OK;
214 }
215 
216 /**
217  * This API sets the method/type of the HTTP response to the value specified.
218  * But the method isn't sent out until any of the send APIs is executed.
219  */
httpd_resp_set_type(httpd_req_t * r,const char * type)220 esp_err_t httpd_resp_set_type(httpd_req_t *r, const char *type)
221 {
222     if (r == NULL || type == NULL) {
223         return ESP_ERR_INVALID_ARG;
224     }
225 
226     if (!httpd_valid_req(r)) {
227         return ESP_ERR_HTTPD_INVALID_REQ;
228     }
229 
230     struct httpd_req_aux *ra = r->aux;
231     ra->content_type = (char *)type;
232     return ESP_OK;
233 }
234 
httpd_resp_send(httpd_req_t * r,const char * buf,ssize_t buf_len)235 esp_err_t httpd_resp_send(httpd_req_t *r, const char *buf, ssize_t buf_len)
236 {
237     if (r == NULL) {
238         return ESP_ERR_INVALID_ARG;
239     }
240 
241     if (!httpd_valid_req(r)) {
242         return ESP_ERR_HTTPD_INVALID_REQ;
243     }
244 
245     struct httpd_req_aux *ra = r->aux;
246     const char *httpd_hdr_str = "HTTP/1.1 %s\r\nContent-Type: %s\r\nContent-Length: %d\r\n";
247     const char *colon_separator = ": ";
248     const char *cr_lf_seperator = "\r\n";
249 
250     if (buf_len == HTTPD_RESP_USE_STRLEN) {
251         buf_len = strlen(buf);
252     }
253 
254     /* Request headers are no longer available */
255     ra->req_hdrs_count = 0;
256 
257     /* Size of essential headers is limited by scratch buffer size */
258     if (snprintf(ra->scratch, sizeof(ra->scratch), httpd_hdr_str,
259                  ra->status, ra->content_type, buf_len) >= sizeof(ra->scratch)) {
260         return ESP_ERR_HTTPD_RESP_HDR;
261     }
262 
263     /* Sending essential headers */
264     if (httpd_send_all(r, ra->scratch, strlen(ra->scratch)) != ESP_OK) {
265         return ESP_ERR_HTTPD_RESP_SEND;
266     }
267 
268     /* Sending additional headers based on set_header */
269     for (unsigned i = 0; i < ra->resp_hdrs_count; i++) {
270         /* Send header field */
271         if (httpd_send_all(r, ra->resp_hdrs[i].field, strlen(ra->resp_hdrs[i].field)) != ESP_OK) {
272             return ESP_ERR_HTTPD_RESP_SEND;
273         }
274         /* Send ': ' */
275         if (httpd_send_all(r, colon_separator, strlen(colon_separator)) != ESP_OK) {
276             return ESP_ERR_HTTPD_RESP_SEND;
277         }
278         /* Send header value */
279         if (httpd_send_all(r, ra->resp_hdrs[i].value, strlen(ra->resp_hdrs[i].value)) != ESP_OK) {
280             return ESP_ERR_HTTPD_RESP_SEND;
281         }
282         /* Send CR + LF */
283         if (httpd_send_all(r, cr_lf_seperator, strlen(cr_lf_seperator)) != ESP_OK) {
284             return ESP_ERR_HTTPD_RESP_SEND;
285         }
286     }
287 
288     /* End header section */
289     if (httpd_send_all(r, cr_lf_seperator, strlen(cr_lf_seperator)) != ESP_OK) {
290         return ESP_ERR_HTTPD_RESP_SEND;
291     }
292 
293     /* Sending content */
294     if (buf && buf_len) {
295         if (httpd_send_all(r, buf, buf_len) != ESP_OK) {
296             return ESP_ERR_HTTPD_RESP_SEND;
297         }
298     }
299     return ESP_OK;
300 }
301 
httpd_resp_send_chunk(httpd_req_t * r,const char * buf,ssize_t buf_len)302 esp_err_t httpd_resp_send_chunk(httpd_req_t *r, const char *buf, ssize_t buf_len)
303 {
304     if (r == NULL) {
305         return ESP_ERR_INVALID_ARG;
306     }
307 
308     if (!httpd_valid_req(r)) {
309         return ESP_ERR_HTTPD_INVALID_REQ;
310     }
311 
312     if (buf_len == HTTPD_RESP_USE_STRLEN) {
313         buf_len = strlen(buf);
314     }
315 
316     struct httpd_req_aux *ra = r->aux;
317     const char *httpd_chunked_hdr_str = "HTTP/1.1 %s\r\nContent-Type: %s\r\nTransfer-Encoding: chunked\r\n";
318     const char *colon_separator = ": ";
319     const char *cr_lf_seperator = "\r\n";
320 
321     /* Request headers are no longer available */
322     ra->req_hdrs_count = 0;
323 
324     if (!ra->first_chunk_sent) {
325         /* Size of essential headers is limited by scratch buffer size */
326         if (snprintf(ra->scratch, sizeof(ra->scratch), httpd_chunked_hdr_str,
327                      ra->status, ra->content_type) >= sizeof(ra->scratch)) {
328             return ESP_ERR_HTTPD_RESP_HDR;
329         }
330 
331         /* Sending essential headers */
332         if (httpd_send_all(r, ra->scratch, strlen(ra->scratch)) != ESP_OK) {
333             return ESP_ERR_HTTPD_RESP_SEND;
334         }
335 
336         /* Sending additional headers based on set_header */
337         for (unsigned i = 0; i < ra->resp_hdrs_count; i++) {
338             /* Send header field */
339             if (httpd_send_all(r, ra->resp_hdrs[i].field, strlen(ra->resp_hdrs[i].field)) != ESP_OK) {
340                 return ESP_ERR_HTTPD_RESP_SEND;
341             }
342             /* Send ': ' */
343             if (httpd_send_all(r, colon_separator, strlen(colon_separator)) != ESP_OK) {
344                 return ESP_ERR_HTTPD_RESP_SEND;
345             }
346             /* Send header value */
347             if (httpd_send_all(r, ra->resp_hdrs[i].value, strlen(ra->resp_hdrs[i].value)) != ESP_OK) {
348                 return ESP_ERR_HTTPD_RESP_SEND;
349             }
350             /* Send CR + LF */
351             if (httpd_send_all(r, cr_lf_seperator, strlen(cr_lf_seperator)) != ESP_OK) {
352                 return ESP_ERR_HTTPD_RESP_SEND;
353             }
354         }
355 
356         /* End header section */
357         if (httpd_send_all(r, cr_lf_seperator, strlen(cr_lf_seperator)) != ESP_OK) {
358             return ESP_ERR_HTTPD_RESP_SEND;
359         }
360         ra->first_chunk_sent = true;
361     }
362 
363     /* Sending chunked content */
364     char len_str[10];
365     snprintf(len_str, sizeof(len_str), "%x\r\n", buf_len);
366     if (httpd_send_all(r, len_str, strlen(len_str)) != ESP_OK) {
367         return ESP_ERR_HTTPD_RESP_SEND;
368     }
369 
370     if (buf) {
371         if (httpd_send_all(r, buf, (size_t) buf_len) != ESP_OK) {
372             return ESP_ERR_HTTPD_RESP_SEND;
373         }
374     }
375 
376     /* Indicate end of chunk */
377     if (httpd_send_all(r, "\r\n", strlen("\r\n")) != ESP_OK) {
378         return ESP_ERR_HTTPD_RESP_SEND;
379     }
380     return ESP_OK;
381 }
382 
httpd_resp_send_err(httpd_req_t * req,httpd_err_code_t error,const char * usr_msg)383 esp_err_t httpd_resp_send_err(httpd_req_t *req, httpd_err_code_t error, const char *usr_msg)
384 {
385     esp_err_t ret;
386     const char *msg;
387     const char *status;
388 
389     switch (error) {
390         case HTTPD_501_METHOD_NOT_IMPLEMENTED:
391             status = "501 Method Not Implemented";
392             msg    = "Request method is not supported by server";
393             break;
394         case HTTPD_505_VERSION_NOT_SUPPORTED:
395             status = "505 Version Not Supported";
396             msg    = "HTTP version not supported by server";
397             break;
398         case HTTPD_400_BAD_REQUEST:
399             status = "400 Bad Request";
400             msg    = "Server unable to understand request due to invalid syntax";
401             break;
402         case HTTPD_401_UNAUTHORIZED:
403             status = "401 Unauthorized";
404             msg    = "Server known the client's identify and it must authenticate itself to get he requested response";
405             break;
406         case HTTPD_403_FORBIDDEN:
407             status = "403 Forbidden";
408             msg    = "Server is refusing to give the requested resource to the client";
409             break;
410         case HTTPD_404_NOT_FOUND:
411             status = "404 Not Found";
412             msg    = "This URI does not exist";
413             break;
414         case HTTPD_405_METHOD_NOT_ALLOWED:
415             status = "405 Method Not Allowed";
416             msg    = "Request method for this URI is not handled by server";
417             break;
418         case HTTPD_408_REQ_TIMEOUT:
419             status = "408 Request Timeout";
420             msg    = "Server closed this connection";
421             break;
422         case HTTPD_414_URI_TOO_LONG:
423             status = "414 URI Too Long";
424             msg    = "URI is too long for server to interpret";
425             break;
426         case HTTPD_411_LENGTH_REQUIRED:
427             status = "411 Length Required";
428             msg    = "Chunked encoding not supported by server";
429             break;
430         case HTTPD_431_REQ_HDR_FIELDS_TOO_LARGE:
431             status = "431 Request Header Fields Too Large";
432             msg    = "Header fields are too long for server to interpret";
433             break;
434         case HTTPD_500_INTERNAL_SERVER_ERROR:
435         default:
436             status = "500 Internal Server Error";
437             msg    = "Server has encountered an unexpected error";
438     }
439 
440     /* If user has provided custom message, override default message */
441     msg = usr_msg ? usr_msg : msg;
442     ESP_LOGW(TAG, LOG_FMT("%s - %s"), status, msg);
443 
444     /* Set error code in HTTP response */
445     httpd_resp_set_status(req, status);
446     httpd_resp_set_type(req, HTTPD_TYPE_TEXT);
447 
448 #ifdef CONFIG_HTTPD_ERR_RESP_NO_DELAY
449     /* Use TCP_NODELAY option to force socket to send data in buffer
450      * This ensures that the error message is sent before the socket
451      * is closed */
452     struct httpd_req_aux *ra = req->aux;
453     int nodelay = 1;
454     if (setsockopt(ra->sd->fd, IPPROTO_TCP, TCP_NODELAY, &nodelay, sizeof(nodelay)) < 0) {
455         /* If failed to turn on TCP_NODELAY, throw warning and continue */
456         ESP_LOGW(TAG, LOG_FMT("error calling setsockopt : %d"), errno);
457         nodelay = 0;
458     }
459 #endif
460 
461     /* Send HTTP error message */
462     ret = httpd_resp_send(req, msg, HTTPD_RESP_USE_STRLEN);
463 
464 #ifdef CONFIG_HTTPD_ERR_RESP_NO_DELAY
465     /* If TCP_NODELAY was set successfully above, time to disable it */
466     if (nodelay == 1) {
467         nodelay = 0;
468         if (setsockopt(ra->sd->fd, IPPROTO_TCP, TCP_NODELAY, &nodelay, sizeof(nodelay)) < 0) {
469             /* If failed to turn off TCP_NODELAY, throw error and
470              * return failure to signal for socket closure */
471             ESP_LOGE(TAG, LOG_FMT("error calling setsockopt : %d"), errno);
472             return ESP_ERR_INVALID_STATE;
473         }
474     }
475 #endif
476 
477     return ret;
478 }
479 
httpd_register_err_handler(httpd_handle_t handle,httpd_err_code_t error,httpd_err_handler_func_t err_handler_fn)480 esp_err_t httpd_register_err_handler(httpd_handle_t handle,
481                                      httpd_err_code_t error,
482                                      httpd_err_handler_func_t err_handler_fn)
483 {
484     if (handle == NULL || error >= HTTPD_ERR_CODE_MAX) {
485         return ESP_ERR_INVALID_ARG;
486     }
487 
488     struct httpd_data *hd = (struct httpd_data *) handle;
489     hd->err_handler_fns[error] = err_handler_fn;
490     return ESP_OK;
491 }
492 
httpd_req_handle_err(httpd_req_t * req,httpd_err_code_t error)493 esp_err_t httpd_req_handle_err(httpd_req_t *req, httpd_err_code_t error)
494 {
495     struct httpd_data *hd = (struct httpd_data *) req->handle;
496     esp_err_t ret;
497 
498     /* Invoke custom error handler if configured */
499     if (hd->err_handler_fns[error]) {
500         ret = hd->err_handler_fns[error](req, error);
501 
502         /* If error code is 500, force return failure
503          * irrespective of the handler's return value */
504         ret = (error == HTTPD_500_INTERNAL_SERVER_ERROR ? ESP_FAIL : ret);
505     } else {
506         /* If no handler is registered for this error default
507          * behavior is to send the HTTP error response and
508          * return failure for closure of underlying socket */
509         httpd_resp_send_err(req, error, NULL);
510         ret = ESP_FAIL;
511     }
512     return ret;
513 }
514 
httpd_req_recv(httpd_req_t * r,char * buf,size_t buf_len)515 int httpd_req_recv(httpd_req_t *r, char *buf, size_t buf_len)
516 {
517     if (r == NULL || buf == NULL) {
518         return HTTPD_SOCK_ERR_INVALID;
519     }
520 
521     if (!httpd_valid_req(r)) {
522         ESP_LOGW(TAG, LOG_FMT("invalid request"));
523         return HTTPD_SOCK_ERR_INVALID;
524     }
525 
526     struct httpd_req_aux *ra = r->aux;
527     ESP_LOGD(TAG, LOG_FMT("remaining length = %d"), ra->remaining_len);
528 
529     if (buf_len > ra->remaining_len) {
530         buf_len = ra->remaining_len;
531     }
532     if (buf_len == 0) {
533         return buf_len;
534     }
535 
536     int ret = httpd_recv(r, buf, buf_len);
537     if (ret < 0) {
538         ESP_LOGD(TAG, LOG_FMT("error in httpd_recv"));
539         return ret;
540     }
541     ra->remaining_len -= ret;
542     ESP_LOGD(TAG, LOG_FMT("received length = %d"), ret);
543     return ret;
544 }
545 
httpd_req_to_sockfd(httpd_req_t * r)546 int httpd_req_to_sockfd(httpd_req_t *r)
547 {
548     if (r == NULL) {
549         return -1;
550     }
551 
552     if (!httpd_valid_req(r)) {
553         ESP_LOGW(TAG, LOG_FMT("invalid request"));
554         return -1;
555     }
556 
557     struct httpd_req_aux *ra = r->aux;
558     return ra->sd->fd;
559 }
560 
httpd_sock_err(const char * ctx,int sockfd)561 static int httpd_sock_err(const char *ctx, int sockfd)
562 {
563     int errval;
564     ESP_LOGW(TAG, LOG_FMT("error in %s : %d"), ctx, errno);
565 
566     switch(errno) {
567     case EAGAIN:
568     case EINTR:
569         errval = HTTPD_SOCK_ERR_TIMEOUT;
570         break;
571     case EINVAL:
572     case EBADF:
573     case EFAULT:
574     case ENOTSOCK:
575         errval = HTTPD_SOCK_ERR_INVALID;
576         break;
577     default:
578         errval = HTTPD_SOCK_ERR_FAIL;
579     }
580     return errval;
581 }
582 
httpd_default_send(httpd_handle_t hd,int sockfd,const char * buf,size_t buf_len,int flags)583 int httpd_default_send(httpd_handle_t hd, int sockfd, const char *buf, size_t buf_len, int flags)
584 {
585     (void)hd;
586     if (buf == NULL) {
587         return HTTPD_SOCK_ERR_INVALID;
588     }
589 
590     int ret = send(sockfd, buf, buf_len, flags);
591     if (ret < 0) {
592         return httpd_sock_err("send", sockfd);
593     }
594     return ret;
595 }
596 
httpd_default_recv(httpd_handle_t hd,int sockfd,char * buf,size_t buf_len,int flags)597 int httpd_default_recv(httpd_handle_t hd, int sockfd, char *buf, size_t buf_len, int flags)
598 {
599     (void)hd;
600     if (buf == NULL) {
601         return HTTPD_SOCK_ERR_INVALID;
602     }
603 
604     int ret = recv(sockfd, buf, buf_len, flags);
605     if (ret < 0) {
606         return httpd_sock_err("recv", sockfd);
607     }
608     return ret;
609 }
610 
httpd_socket_send(httpd_handle_t hd,int sockfd,const char * buf,size_t buf_len,int flags)611 int httpd_socket_send(httpd_handle_t hd, int sockfd, const char *buf, size_t buf_len, int flags)
612 {
613     struct sock_db *sess = httpd_sess_get(hd, sockfd);
614     if (!sess) {
615         return ESP_ERR_INVALID_ARG;
616     }
617     if (!sess->send_fn) {
618         return ESP_ERR_INVALID_STATE;
619     }
620     return sess->send_fn(hd, sockfd, buf, buf_len, flags);
621 }
622 
httpd_socket_recv(httpd_handle_t hd,int sockfd,char * buf,size_t buf_len,int flags)623 int httpd_socket_recv(httpd_handle_t hd, int sockfd, char *buf, size_t buf_len, int flags)
624 {
625     struct sock_db *sess = httpd_sess_get(hd, sockfd);
626     if (!sess) {
627         return ESP_ERR_INVALID_ARG;
628     }
629     if (!sess->recv_fn) {
630         return ESP_ERR_INVALID_STATE;
631     }
632     return sess->recv_fn(hd, sockfd, buf, buf_len, flags);
633 }
634