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