1 /* Copyright  (C) 2010-2018 The RetroArch team
2  *
3  * ---------------------------------------------------------------------------------------
4  * The following license statement only applies to this file (net_http.c).
5  * ---------------------------------------------------------------------------------------
6  *
7  * Permission is hereby granted, free of charge,
8  * to any person obtaining a copy of this software and associated documentation files (the "Software"),
9  * to deal in the Software without restriction, including without limitation the rights to
10  * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software,
11  * and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
12  *
13  * The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
14  *
15  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
16  * INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18  * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
19  * WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20  * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
21  */
22 
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <ctype.h>
26 
27 #include <net/net_http.h>
28 #include <net/net_compat.h>
29 #include <net/net_socket.h>
30 #ifdef HAVE_SSL
31 #include <net/net_socket_ssl.h>
32 #endif
33 #include <compat/strl.h>
34 #include <string/stdstring.h>
35 #include <string.h>
36 #include <retro_common_api.h>
37 #include <retro_miscellaneous.h>
38 
39 enum
40 {
41    P_HEADER_TOP = 0,
42    P_HEADER,
43    P_BODY,
44    P_BODY_CHUNKLEN,
45    P_DONE,
46    P_ERROR
47 };
48 
49 enum
50 {
51    T_FULL = 0,
52    T_LEN,
53    T_CHUNK
54 };
55 
56 struct http_socket_state_t
57 {
58    int fd;
59    bool ssl;
60    void *ssl_ctx;
61 };
62 
63 struct http_t
64 {
65    int status;
66 
67    char part;
68    char bodytype;
69    bool error;
70 
71    size_t pos;
72    size_t len;
73    size_t buflen;
74    char *data;
75    struct http_socket_state_t sock_state;
76 };
77 
78 struct http_connection_t
79 {
80    char *domain;
81    char *location;
82    char *urlcopy;
83    char *scan;
84    char *methodcopy;
85    char *contenttypecopy;
86    char *postdatacopy;
87    int port;
88    struct http_socket_state_t sock_state;
89 };
90 
91 static char urlencode_lut[256];
92 static bool urlencode_lut_inited = false;
93 
urlencode_lut_init(void)94 void urlencode_lut_init(void)
95 {
96    unsigned i;
97 
98    urlencode_lut_inited = true;
99 
100    for (i = 0; i < 256; i++)
101    {
102       urlencode_lut[i] = isalnum(i) || i == '*' || i == '-' || i == '.' || i == '_' || i == '/' ? i : 0;
103    }
104 }
105 
106 /* URL Encode a string
107    caller is responsible for deleting the destination buffer */
net_http_urlencode(char ** dest,const char * source)108 void net_http_urlencode(char **dest, const char *source)
109 {
110    char *enc    = NULL;
111    /* Assume every character will be encoded, so we need 3 times the space. */
112    size_t len   = strlen(source) * 3 + 1;
113    size_t count = len;
114 
115    if (!urlencode_lut_inited)
116       urlencode_lut_init();
117 
118    enc   = (char*)calloc(1, len);
119 
120    *dest = enc;
121 
122    for (; *source; source++)
123    {
124       int written = 0;
125 
126       /* any non-ascii character will just be encoded without question */
127       if ((unsigned)*source < sizeof(urlencode_lut) && urlencode_lut[(unsigned)*source])
128          written = snprintf(enc, count, "%c", urlencode_lut[(unsigned)*source]);
129       else
130          written = snprintf(enc, count, "%%%02X", *source & 0xFF);
131 
132       if (written > 0)
133          count -= written;
134 
135       while (*++enc);
136    }
137 
138    (*dest)[len - 1] = '\0';
139 }
140 
141 /* Re-encode a full URL */
net_http_urlencode_full(char * dest,const char * source,size_t size)142 void net_http_urlencode_full(char *dest,
143       const char *source, size_t size)
144 {
145    char *tmp                         = NULL;
146    char url_domain[PATH_MAX_LENGTH]  = {0};
147    char url_path[PATH_MAX_LENGTH]    = {0};
148    int count                         = 0;
149 
150    strlcpy(url_path, source, sizeof(url_path));
151    tmp = url_path;
152 
153    while (count < 3 && tmp[0] != '\0')
154    {
155       tmp = strchr(tmp, '/');
156       count++;
157       tmp++;
158    }
159 
160    strlcpy(url_domain, source, tmp - url_path);
161 
162    strlcpy(url_path,
163          source + strlen(url_domain) + 1,
164          strlen(tmp) + 1
165          );
166 
167    tmp = NULL;
168    net_http_urlencode(&tmp, url_path);
169    snprintf(dest, size, "%s/%s", url_domain, tmp);
170    free (tmp);
171 }
172 
net_http_new_socket(struct http_connection_t * conn)173 static int net_http_new_socket(struct http_connection_t *conn)
174 {
175    int ret;
176    struct addrinfo *addr = NULL, *next_addr = NULL;
177    int fd                = socket_init(
178          (void**)&addr, conn->port, conn->domain, SOCKET_TYPE_STREAM);
179 #ifdef HAVE_SSL
180    if (conn->sock_state.ssl)
181    {
182       if (!(conn->sock_state.ssl_ctx = ssl_socket_init(fd, conn->domain)))
183          return -1;
184    }
185 #endif
186 
187    next_addr = addr;
188    while(fd >= 0)
189    {
190 #ifdef HAVE_SSL
191       if (conn->sock_state.ssl)
192       {
193          ret = ssl_socket_connect(conn->sock_state.ssl_ctx,
194                (void*)next_addr, true, true);
195 
196          if (ret >= 0)
197             break;
198 
199          ssl_socket_close(conn->sock_state.ssl_ctx);
200       }
201       else
202 #endif
203       {
204          ret = socket_connect(fd, (void*)next_addr, true);
205 
206          if (ret >= 0 && socket_nonblock(fd))
207             break;
208 
209          socket_close(fd);
210       }
211 
212       fd = socket_next((void**)&next_addr);
213    }
214 
215    if (addr)
216       freeaddrinfo_retro(addr);
217 
218    conn->sock_state.fd = fd;
219 
220    return fd;
221 }
222 
net_http_send_str(struct http_socket_state_t * sock_state,bool * error,const char * text)223 static void net_http_send_str(
224       struct http_socket_state_t *sock_state, bool *error, const char *text)
225 {
226    size_t text_size;
227    if (*error)
228       return;
229    text_size = strlen(text);
230 #ifdef HAVE_SSL
231    if (sock_state->ssl)
232    {
233       if (!ssl_socket_send_all_blocking(
234                sock_state->ssl_ctx, text, text_size, true))
235          *error = true;
236    }
237    else
238 #endif
239    {
240       if (!socket_send_all_blocking(
241                sock_state->fd, text, text_size, true))
242          *error = true;
243    }
244 }
245 
net_http_connection_new(const char * url,const char * method,const char * data)246 struct http_connection_t *net_http_connection_new(const char *url,
247       const char *method, const char *data)
248 {
249    char new_domain[2048];
250    bool error                     = false;
251    char **domain                  = NULL;
252    char *uri                      = NULL;
253    char *url_dup                  = NULL;
254    char *domain_port              = NULL;
255    char *domain_port2             = NULL;
256    char *url_port                 = NULL;
257 
258    struct http_connection_t *conn = (struct http_connection_t*)calloc(1,
259          sizeof(*conn));
260 
261    if (!conn)
262       return NULL;
263 
264    if (!url)
265    {
266       free(conn);
267       return NULL;
268    }
269 
270    conn->urlcopy           = strdup(url);
271 
272    if (method)
273       conn->methodcopy     = strdup(method);
274 
275    if (data)
276       conn->postdatacopy   = strdup(data);
277 
278    if (!conn->urlcopy)
279       goto error;
280 
281    if (!strncmp(url, "http://", STRLEN_CONST("http://")))
282       conn->scan           = conn->urlcopy + STRLEN_CONST("http://");
283    else if (!strncmp(url, "https://", STRLEN_CONST("https://")))
284    {
285       conn->scan           = conn->urlcopy + STRLEN_CONST("https://");
286       conn->sock_state.ssl = true;
287    }
288    else
289       error = true;
290 
291    if (string_is_empty(conn->scan))
292       goto error;
293 
294    /* Get the port here from the url if it's specified.
295       does not work on username password urls: user:pass@domain.com
296 
297       This code is not supposed to be needed, since the port
298       should be gotten elsewhere when the url is being scanned
299       for ":", but for whatever reason, it's not working correctly.
300    */
301 
302    uri = strchr(conn->scan, (char) '/');
303 
304    if (strchr(conn->scan, (char) ':') != NULL)
305    {
306       url_dup      = strdup(conn->scan);
307       domain_port  = strtok(url_dup, ":");
308       domain_port2 = strtok(NULL, ":");
309       url_port     = domain_port2;
310       if (strchr(domain_port2, (char) '/') != NULL)
311          url_port  = strtok(domain_port2, "/");
312 
313       if (url_port != NULL)
314          conn->port = atoi(url_port);
315 
316       strlcpy(new_domain, domain_port, sizeof(new_domain));
317 
318       free(url_dup);
319 
320       if (uri != NULL)
321       {
322          if (strchr(uri, (char) '/') == NULL)
323             strlcat(new_domain, uri, sizeof(new_domain));
324          else
325          {
326             strlcat(new_domain, "/", sizeof(new_domain));
327             strlcat(new_domain, strchr(uri, (char) '/')+sizeof(char), sizeof(new_domain));
328          }
329          strlcpy(conn->scan, new_domain, strlen(conn->scan) + 1);
330       }
331    }
332    /* end of port-fetching from url  */
333    if (error)
334       goto error;
335 
336    domain        = &conn->domain;
337    *domain       = conn->scan;
338 
339    return conn;
340 
341 error:
342    if (conn->urlcopy)
343       free(conn->urlcopy);
344    if (conn->methodcopy)
345       free(conn->methodcopy);
346    if (conn->postdatacopy)
347       free(conn->postdatacopy);
348    conn->urlcopy      = NULL;
349    conn->methodcopy   = NULL;
350    conn->postdatacopy = NULL;
351    free(conn);
352    return NULL;
353 }
354 
net_http_connection_iterate(struct http_connection_t * conn)355 bool net_http_connection_iterate(struct http_connection_t *conn)
356 {
357    if (!conn)
358       return false;
359 
360    while (*conn->scan != '/' && *conn->scan != ':' && *conn->scan != '\0')
361       conn->scan++;
362 
363    return true;
364 }
365 
net_http_connection_done(struct http_connection_t * conn)366 bool net_http_connection_done(struct http_connection_t *conn)
367 {
368    char **location = NULL;
369 
370    if (!conn)
371       return false;
372 
373    location     = &conn->location;
374 
375    if (*conn->scan == '\0')
376       return false;
377    *conn->scan  = '\0';
378 
379    if (conn->port == 0)
380    {
381       if (conn->sock_state.ssl)
382          conn->port   = 443;
383       else
384          conn->port   = 80;
385    }
386 
387    if (*conn->scan == ':')
388    {
389       if (!isdigit((int)conn->scan[1]))
390          return false;
391 
392       conn->port = (int)strtoul(conn->scan + 1, &conn->scan, 10);
393 
394       if (*conn->scan != '/')
395          return false;
396    }
397 
398    *location = conn->scan + 1;
399 
400    return true;
401 }
402 
net_http_connection_free(struct http_connection_t * conn)403 void net_http_connection_free(struct http_connection_t *conn)
404 {
405    if (!conn)
406       return;
407 
408    if (conn->urlcopy)
409       free(conn->urlcopy);
410 
411    if (conn->methodcopy)
412       free(conn->methodcopy);
413 
414    if (conn->contenttypecopy)
415       free(conn->contenttypecopy);
416 
417    if (conn->postdatacopy)
418       free(conn->postdatacopy);
419 
420    conn->urlcopy         = NULL;
421    conn->methodcopy      = NULL;
422    conn->contenttypecopy = NULL;
423    conn->postdatacopy    = NULL;
424 
425    free(conn);
426 }
427 
net_http_connection_url(struct http_connection_t * conn)428 const char *net_http_connection_url(struct http_connection_t *conn)
429 {
430    return conn->urlcopy;
431 }
432 
net_http_new(struct http_connection_t * conn)433 struct http_t *net_http_new(struct http_connection_t *conn)
434 {
435    bool error            = false;
436    int fd                = -1;
437    struct http_t *state  = NULL;
438 
439    if (!conn)
440       goto error;
441 
442    fd = net_http_new_socket(conn);
443 
444    if (fd < 0)
445       goto error;
446 
447    error = false;
448 
449    /* This is a bit lazy, but it works. */
450    if (conn->methodcopy)
451    {
452       net_http_send_str(&conn->sock_state, &error, conn->methodcopy);
453       net_http_send_str(&conn->sock_state, &error, " /");
454    }
455    else
456    {
457       net_http_send_str(&conn->sock_state, &error, "GET /");
458    }
459 
460    net_http_send_str(&conn->sock_state, &error, conn->location);
461    net_http_send_str(&conn->sock_state, &error, " HTTP/1.1\r\n");
462 
463    net_http_send_str(&conn->sock_state, &error, "Host: ");
464    net_http_send_str(&conn->sock_state, &error, conn->domain);
465 
466    if (!conn->port)
467    {
468       char portstr[16];
469 
470       portstr[0] = '\0';
471 
472       snprintf(portstr, sizeof(portstr), ":%i", conn->port);
473       net_http_send_str(&conn->sock_state, &error, portstr);
474    }
475 
476    net_http_send_str(&conn->sock_state, &error, "\r\n");
477 
478    /* this is not being set anywhere yet */
479    if (conn->contenttypecopy)
480    {
481       net_http_send_str(&conn->sock_state, &error, "Content-Type: ");
482       net_http_send_str(&conn->sock_state, &error, conn->contenttypecopy);
483       net_http_send_str(&conn->sock_state, &error, "\r\n");
484    }
485 
486    if (conn->methodcopy && (string_is_equal(conn->methodcopy, "POST")))
487    {
488       size_t post_len, len;
489       char *len_str        = NULL;
490 
491       if (!conn->postdatacopy)
492          goto error;
493 
494       if (!conn->contenttypecopy)
495          net_http_send_str(&conn->sock_state, &error,
496                "Content-Type: application/x-www-form-urlencoded\r\n");
497 
498       net_http_send_str(&conn->sock_state, &error, "Content-Length: ");
499 
500       post_len = strlen(conn->postdatacopy);
501 #ifdef _WIN32
502       len     = snprintf(NULL, 0, "%" PRIuPTR, post_len);
503       len_str = (char*)malloc(len + 1);
504       snprintf(len_str, len + 1, "%" PRIuPTR, post_len);
505 #else
506       len     = snprintf(NULL, 0, "%llu", (long long unsigned)post_len);
507       len_str = (char*)malloc(len + 1);
508       snprintf(len_str, len + 1, "%llu", (long long unsigned)post_len);
509 #endif
510 
511       len_str[len] = '\0';
512 
513       net_http_send_str(&conn->sock_state, &error, len_str);
514       net_http_send_str(&conn->sock_state, &error, "\r\n");
515 
516       free(len_str);
517    }
518 
519    net_http_send_str(&conn->sock_state, &error, "User-Agent: libretro\r\n");
520    net_http_send_str(&conn->sock_state, &error, "Connection: close\r\n");
521    net_http_send_str(&conn->sock_state, &error, "\r\n");
522 
523    if (conn->methodcopy && (string_is_equal(conn->methodcopy, "POST")))
524       net_http_send_str(&conn->sock_state, &error, conn->postdatacopy);
525 
526    if (error)
527       goto error;
528 
529    state             = (struct http_t*)malloc(sizeof(struct http_t));
530    state->sock_state = conn->sock_state;
531    state->status     = -1;
532    state->data       = NULL;
533    state->part       = P_HEADER_TOP;
534    state->bodytype   = T_FULL;
535    state->error      = false;
536    state->pos        = 0;
537    state->len        = 0;
538    state->buflen     = 512;
539    state->data       = (char*)malloc(state->buflen);
540 
541    if (!state->data)
542       goto error;
543 
544    return state;
545 
546 error:
547    if (conn)
548    {
549       if (conn->methodcopy)
550          free(conn->methodcopy);
551       if (conn->contenttypecopy)
552          free(conn->contenttypecopy);
553       conn->methodcopy = NULL;
554       conn->contenttypecopy = NULL;
555       conn->postdatacopy = NULL;
556    }
557 #ifdef HAVE_SSL
558    if (conn && conn->sock_state.ssl && conn->sock_state.ssl_ctx && fd >= 0)
559    {
560       ssl_socket_close(conn->sock_state.ssl_ctx);
561       ssl_socket_free(conn->sock_state.ssl_ctx);
562       conn->sock_state.ssl_ctx = NULL;
563    }
564 #else
565    if (fd >= 0)
566       socket_close(fd);
567 #endif
568    if (state)
569       free(state);
570    return NULL;
571 }
572 
net_http_fd(struct http_t * state)573 int net_http_fd(struct http_t *state)
574 {
575    if (!state)
576       return -1;
577    return state->sock_state.fd;
578 }
579 
net_http_update(struct http_t * state,size_t * progress,size_t * total)580 bool net_http_update(struct http_t *state, size_t* progress, size_t* total)
581 {
582    ssize_t newlen = 0;
583 
584    if (!state || state->error)
585       goto fail;
586 
587    if (state->part < P_BODY)
588    {
589       if (state->error)
590          newlen = -1;
591       else
592       {
593 #ifdef HAVE_SSL
594          if (state->sock_state.ssl && state->sock_state.ssl_ctx)
595             newlen = ssl_socket_receive_all_nonblocking(state->sock_state.ssl_ctx, &state->error,
596                (uint8_t*)state->data + state->pos,
597                state->buflen - state->pos);
598          else
599 #endif
600             newlen = socket_receive_all_nonblocking(state->sock_state.fd, &state->error,
601                (uint8_t*)state->data + state->pos,
602                state->buflen - state->pos);
603       }
604 
605       if (newlen < 0)
606          goto fail;
607 
608       if (state->pos + newlen >= state->buflen - 64)
609       {
610          state->buflen *= 2;
611          state->data    = (char*)realloc(state->data, state->buflen);
612       }
613       state->pos += newlen;
614 
615       while (state->part < P_BODY)
616       {
617          char *dataend = state->data + state->pos;
618          char *lineend = (char*)memchr(state->data, '\n', state->pos);
619 
620          if (!lineend)
621             break;
622 
623          *lineend='\0';
624 
625          if (lineend != state->data && lineend[-1]=='\r')
626             lineend[-1]='\0';
627 
628          if (state->part == P_HEADER_TOP)
629          {
630             if (strncmp(state->data, "HTTP/1.", STRLEN_CONST("HTTP/1."))!=0)
631                goto fail;
632             state->status = (int)strtoul(state->data
633                   + STRLEN_CONST("HTTP/1.1 "), NULL, 10);
634             state->part   = P_HEADER;
635          }
636          else
637          {
638             if (!strncmp(state->data, "Content-Length: ",
639                      STRLEN_CONST("Content-Length: ")))
640             {
641                state->bodytype = T_LEN;
642                state->len = strtol(state->data +
643                      STRLEN_CONST("Content-Length: "), NULL, 10);
644             }
645             if (string_is_equal(state->data, "Transfer-Encoding: chunked"))
646                state->bodytype = T_CHUNK;
647 
648             /* TODO: save headers somewhere */
649             if (state->data[0]=='\0')
650             {
651                state->part = P_BODY;
652                if (state->bodytype == T_CHUNK)
653                   state->part = P_BODY_CHUNKLEN;
654             }
655          }
656 
657          memmove(state->data, lineend + 1, dataend-(lineend+1));
658          state->pos = (dataend-(lineend + 1));
659       }
660       if (state->part >= P_BODY)
661       {
662          newlen = state->pos;
663          state->pos = 0;
664       }
665    }
666 
667    if (state->part >= P_BODY && state->part < P_DONE)
668    {
669       if (!newlen)
670       {
671          if (state->error)
672             newlen = -1;
673          else
674          {
675 #ifdef HAVE_SSL
676             if (state->sock_state.ssl && state->sock_state.ssl_ctx)
677                newlen = ssl_socket_receive_all_nonblocking(
678                   state->sock_state.ssl_ctx,
679                   &state->error,
680                   (uint8_t*)state->data + state->pos,
681                   state->buflen - state->pos);
682             else
683 #endif
684                newlen = socket_receive_all_nonblocking(
685                   state->sock_state.fd,
686                   &state->error,
687                   (uint8_t*)state->data + state->pos,
688                   state->buflen - state->pos);
689          }
690 
691          if (newlen < 0)
692          {
693             if (state->bodytype == T_FULL)
694             {
695                state->part = P_DONE;
696                state->data = (char*)realloc(state->data, state->len);
697             }
698             else
699                goto fail;
700             newlen=0;
701          }
702 
703          if (state->pos + newlen >= state->buflen - 64)
704          {
705             state->buflen *= 2;
706             state->data = (char*)realloc(state->data, state->buflen);
707          }
708       }
709 
710 parse_again:
711       if (state->bodytype == T_CHUNK)
712       {
713          if (state->part == P_BODY_CHUNKLEN)
714          {
715             state->pos += newlen;
716             if (state->pos - state->len >= 2)
717             {
718                /*
719                 * len=start of chunk including \r\n
720                 * pos=end of data
721                 */
722 
723                char *fullend = state->data + state->pos;
724                char *end     = (char*)memchr(state->data + state->len + 2, '\n',
725                                              state->pos - state->len - 2);
726 
727                if (end)
728                {
729                   size_t chunklen = strtoul(state->data+state->len, NULL, 16);
730                   state->pos      = state->len;
731                   end++;
732 
733                   memmove(state->data+state->len, end, fullend-end);
734 
735                   state->len      = chunklen;
736                   newlen          = (fullend - end);
737 
738                   /*
739                      len=num bytes
740                      newlen=unparsed bytes after \n
741                      pos=start of chunk including \r\n
742                      */
743 
744                   state->part = P_BODY;
745                   if (state->len == 0)
746                   {
747                      state->part = P_DONE;
748                      state->len  = state->pos;
749                      state->data = (char*)realloc(state->data, state->len);
750                   }
751                   goto parse_again;
752                }
753             }
754          }
755          else if (state->part == P_BODY)
756          {
757             if ((size_t)newlen >= state->len)
758             {
759                state->pos += state->len;
760                newlen     -= state->len;
761                state->len  = state->pos;
762                state->part = P_BODY_CHUNKLEN;
763                goto parse_again;
764             }
765             else
766             {
767                state->pos += newlen;
768                state->len -= newlen;
769             }
770          }
771       }
772       else
773       {
774          state->pos += newlen;
775 
776          if (state->pos == state->len)
777          {
778             state->part = P_DONE;
779             state->data = (char*)realloc(state->data, state->len);
780          }
781          if (state->pos > state->len)
782             goto fail;
783       }
784    }
785 
786    if (progress)
787       *progress = state->pos;
788 
789    if (total)
790    {
791       if (state->bodytype == T_LEN)
792          *total=state->len;
793       else
794          *total=0;
795    }
796 
797    return (state->part == P_DONE);
798 
799 fail:
800    if (state)
801    {
802       state->error  = true;
803       state->part   = P_ERROR;
804       state->status = -1;
805    }
806 
807    return true;
808 }
809 
net_http_status(struct http_t * state)810 int net_http_status(struct http_t *state)
811 {
812    if (!state)
813       return -1;
814    return state->status;
815 }
816 
net_http_data(struct http_t * state,size_t * len,bool accept_error)817 uint8_t* net_http_data(struct http_t *state, size_t* len, bool accept_error)
818 {
819    if (!state)
820       return NULL;
821 
822    if (!accept_error && net_http_error(state))
823    {
824       if (len)
825          *len=0;
826       return NULL;
827    }
828 
829    if (len)
830       *len=state->len;
831 
832    return (uint8_t*)state->data;
833 }
834 
net_http_delete(struct http_t * state)835 void net_http_delete(struct http_t *state)
836 {
837    if (!state)
838       return;
839 
840    if (state->sock_state.fd >= 0)
841    {
842       socket_close(state->sock_state.fd);
843 #ifdef HAVE_SSL
844       if (state->sock_state.ssl && state->sock_state.ssl_ctx)
845       {
846          ssl_socket_free(state->sock_state.ssl_ctx);
847          state->sock_state.ssl_ctx = NULL;
848       }
849 #endif
850    }
851    free(state);
852 }
853 
net_http_error(struct http_t * state)854 bool net_http_error(struct http_t *state)
855 {
856    return (state->error || state->status<200 || state->status>299);
857 }
858