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