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