1 /*
2  *  Tvheadend - HTTP client functions
3  *
4  *  Copyright (C) 2014 Jaroslav Kysela
5  *
6  *  This program is free software: you can redistribute it and/or modify
7  *  it under the terms of the GNU General Public License as published by
8  *  the Free Software Foundation, either version 3 of the License, or
9  *  (at your option) any later version.
10  *
11  *  This program is distributed in the hope that it will be useful,
12  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
13  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  *  GNU General Public License for more details.
15  *
16  *  You should have received a copy of the GNU General Public License
17  *  along with this program.  If not, see <http://www.gnu.org/licenses/>.
18  */
19 
20 #include "tvheadend.h"
21 #include "http.h"
22 #include "tcp.h"
23 
24 #include <pthread.h>
25 #include <unistd.h>
26 #include <stdlib.h>
27 #include <signal.h>
28 #include <fcntl.h>
29 #include <poll.h>
30 
31 #if defined(PLATFORM_FREEBSD)
32 #include <sys/types.h>
33 #include <sys/socket.h>
34 #endif
35 
36 #include <openssl/err.h>
37 #include <openssl/ssl.h>
38 
39 #ifndef SSL_OP_NO_COMPRESSION
40 #define SSL_OP_NO_COMPRESSION 0
41 #endif
42 
43 #if ENABLE_ANDROID
44 #include <sys/socket.h>
45 #endif
46 
47 struct http_client_ssl {
48   int      connected;
49   int      shutdown;
50   int      notified;
51 
52   SSL_CTX *ctx;
53   SSL     *ssl;
54 
55   BIO     *rbio;
56   char    *rbio_buf;
57   size_t   rbio_size;
58   size_t   rbio_pos;
59 
60   BIO     *wbio;
61   char    *wbio_buf;
62   size_t   wbio_size;
63   size_t   wbio_pos;
64 };
65 
66 static int
67 http_client_redirected ( http_client_t *hc );
68 static int
69 http_client_ssl_write_update( http_client_t *hc );
70 static int
71 http_client_reconnect
72   ( http_client_t *hc, http_ver_t ver, const char *scheme,
73     const char *host, int port );
74 #if HTTPCLIENT_TESTSUITE
75 static void
76 http_client_testsuite_run( void );
77 #endif
78 
79 /*
80  * Global state
81  */
82 static int                      http_running;
83 static tvhpoll_t               *http_poll;
84 static TAILQ_HEAD(,http_client) http_clients;
85 static pthread_mutex_t          http_lock;
86 static tvh_cond_t               http_cond;
87 static th_pipe_t                http_pipe;
88 static char                    *http_user_agent;
89 
90 /*
91  *
92  */
93 static inline int
shortid(http_client_t * hc)94 shortid( http_client_t *hc )
95 {
96   return hc->hc_id;
97 }
98 
99 /*
100  *
101  */
102 static void
http_client_get(http_client_t * hc)103 http_client_get( http_client_t *hc )
104 {
105   hc->hc_refcnt++;
106 }
107 
108 static void
http_client_put(http_client_t * hc)109 http_client_put( http_client_t *hc )
110 {
111   hc->hc_refcnt--;
112 }
113 
114 static int
http_client_busy(http_client_t * hc)115 http_client_busy( http_client_t *hc )
116 {
117   return !!hc->hc_refcnt;
118 }
119 
120 /*
121  *
122  */
123 static int
http_port(http_client_t * hc,const char * scheme,int port)124 http_port( http_client_t *hc, const char *scheme, int port )
125 {
126   if (port <= 0 || port > 65535) {
127     if (scheme && strcmp(scheme, "http") == 0)
128       port = 80;
129     else if (scheme && strcmp(scheme, "https") == 0)
130       port = 443;
131     else if (scheme && strcmp(scheme, "rtsp") == 0)
132       port = 554;
133     else {
134       tvherror(LS_HTTPC, "%04X: Unknown scheme '%s'", shortid(hc), scheme ? scheme : "");
135       return -EINVAL;
136     }
137   }
138   return port;
139 }
140 
141 /*
142  * Disable
143  */
144 static void
http_client_shutdown(http_client_t * hc,int force,int reconnect)145 http_client_shutdown ( http_client_t *hc, int force, int reconnect )
146 {
147   struct http_client_ssl *ssl = hc->hc_ssl;
148 
149   tvhtrace(LS_HTTPC, "%04X: shutdown", shortid(hc));
150   hc->hc_shutdown = 1;
151   if (ssl) {
152     if (!ssl->shutdown) {
153       SSL_shutdown(hc->hc_ssl->ssl);
154       http_client_ssl_write_update(hc);
155       ssl->shutdown = 1;
156     }
157     if (!force)
158       return;
159   }
160   if (hc->hc_efd) {
161     tvhpoll_event_t ev;
162     memset(&ev, 0, sizeof(ev));
163     ev.fd       = hc->hc_fd;
164     tvhpoll_rem(hc->hc_efd, &ev, 1);
165     if (hc->hc_efd == http_poll && !reconnect) {
166       pthread_mutex_lock(&http_lock);
167       TAILQ_REMOVE(&http_clients, hc, hc_link);
168       hc->hc_efd = NULL;
169       pthread_mutex_unlock(&http_lock);
170     } else {
171       hc->hc_efd  = NULL;
172     }
173   }
174   if (hc->hc_fd >= 0) {
175     if (hc->hc_conn_closed) {
176       http_client_get(hc);
177       pthread_mutex_unlock(&hc->hc_mutex);
178       hc->hc_conn_closed(hc, -hc->hc_result);
179       pthread_mutex_lock(&hc->hc_mutex);
180       http_client_put(hc);
181     }
182     if (hc->hc_fd >= 0)
183       close(hc->hc_fd);
184     hc->hc_fd = -1;
185   }
186 }
187 
188 /*
189  * Poll I/O
190  */
191 static void
http_client_poll_dir(http_client_t * hc,int in,int out)192 http_client_poll_dir ( http_client_t *hc, int in, int out )
193 {
194   int events = (in ? TVHPOLL_IN : 0) | (out ? TVHPOLL_OUT : 0);
195   tvhpoll_event_t ev;
196   if (hc->hc_efd) {
197     if (events == 0 && hc->hc_pause) {
198       tvhtrace(LS_HTTPC, "%04X: pausing input", shortid(hc));
199       if (hc->hc_pevents_pause == 0)
200         hc->hc_pevents_pause = hc->hc_pevents;
201       memset(&ev, 0, sizeof(ev));
202       ev.fd       = hc->hc_fd;
203       ev.data.ptr = hc;
204       tvhpoll_rem(hc->hc_efd, &ev, 1);
205     } else if (hc->hc_pevents != events) {
206       tvhtrace(LS_HTTPC, "%04X: add poll for input%s (%x)", shortid(hc), out ? " and output" : "", events);
207       memset(&ev, 0, sizeof(ev));
208       ev.fd       = hc->hc_fd;
209       ev.events   = events | TVHPOLL_IN;
210       ev.data.ptr = hc;
211       tvhpoll_add(hc->hc_efd, &ev, 1);
212     }
213   }
214   hc->hc_pevents = events;
215   /* make sure to set the correct errno for our SSL routines */
216   errno = EAGAIN;
217 }
218 
219 void
http_client_unpause(http_client_t * hc)220 http_client_unpause( http_client_t *hc )
221 {
222   if (hc->hc_pause) {
223     int pevents_pause = hc->hc_pevents_pause;
224     tvhtrace(LS_HTTPC, "%04X: resuming input", shortid(hc));
225     hc->hc_pause = 0;
226     hc->hc_pevents_pause = 0;
227     http_client_poll_dir(hc, pevents_pause & TVHPOLL_IN,
228             pevents_pause & TVHPOLL_OUT);
229   }
230 }
231 
232 static void
http_client_direction(http_client_t * hc,int sending)233 http_client_direction ( http_client_t *hc, int sending )
234 {
235   hc->hc_sending = sending;
236   if (hc->hc_ssl == NULL)
237     http_client_poll_dir(hc, 1, sending);
238 }
239 
240 /*
241  * Main I/O routines
242  */
243 
244 static inline void
http_client_rbuf_cut(http_client_t * hc,size_t cut)245 http_client_rbuf_cut( http_client_t *hc, size_t cut )
246 {
247   size_t len = hc->hc_rpos - cut;
248   memmove(hc->hc_rbuf, hc->hc_rbuf + cut, len);
249   hc->hc_rpos = len;
250 }
251 
252 static void
http_client_cmd_destroy(http_client_t * hc,http_client_wcmd_t * cmd)253 http_client_cmd_destroy( http_client_t *hc, http_client_wcmd_t *cmd )
254 {
255   TAILQ_REMOVE(&hc->hc_wqueue, cmd, link);
256   free(cmd->wbuf);
257   free(cmd);
258 }
259 
260 static int
http_client_flush(http_client_t * hc,int result)261 http_client_flush( http_client_t *hc, int result )
262 {
263   hc->hc_result       = result;
264   tvhtrace(LS_HTTPC, "%04X: client flush %i", shortid(hc), result);
265   if (result < 0)
266     http_client_shutdown(hc, 0, 0);
267   hc->hc_in_data      = 0;
268   hc->hc_in_rtp_data  = 0;
269   hc->hc_hsize        = 0;
270   hc->hc_csize        = 0;
271   hc->hc_rpos         = 0;
272   hc->hc_chunked      = 0;
273   free(hc->hc_chunk);
274   hc->hc_chunk        = 0;
275   hc->hc_chunk_pos    = 0;
276   hc->hc_chunk_size   = 0;
277   hc->hc_chunk_csize  = 0;
278   hc->hc_chunk_alloc  = 0;
279   hc->hc_chunk_trails = 0;
280   http_arg_flush(&hc->hc_args);
281   return result;
282 }
283 
284 int
http_client_clear_state(http_client_t * hc)285 http_client_clear_state( http_client_t *hc )
286 {
287   if (hc->hc_shutdown)
288     return -EBADF;
289   free(hc->hc_data);
290   hc->hc_data = NULL;
291   hc->hc_data_size = 0;
292   return http_client_flush(hc, 0);
293 }
294 
295 static int
http_client_einprogress(http_client_t * hc)296 http_client_einprogress( http_client_t *hc )
297 {
298   struct pollfd fds;
299   fds.fd      = hc->hc_fd;
300   fds.events  = POLLOUT|POLLNVAL|POLLERR;
301   fds.revents = 0;
302   if (poll(&fds, 1, 0) == 0) {
303     http_client_poll_dir(hc, 0, 1);
304     return 1;
305   }
306   hc->hc_einprogress = 0;
307   return 0;
308 }
309 
310 static int
http_client_ssl_read_update(http_client_t * hc)311 http_client_ssl_read_update( http_client_t *hc )
312 {
313   struct http_client_ssl *ssl = hc->hc_ssl;
314   char *rbuf = alloca(hc->hc_io_size);
315   ssize_t r, r2;
316   size_t len;
317 
318   if (ssl->rbio_pos > 0) {
319     r = BIO_write(ssl->rbio, ssl->rbio_buf, ssl->rbio_pos);
320     if (r >= 0) {
321       memmove(ssl->rbio_buf, ssl->rbio_buf + r, ssl->rbio_pos - r);
322       ssl->rbio_pos -= r;
323     } else if (r < 0) {
324       errno = EIO;
325       return -1;
326     }
327   }
328   r = recv(hc->hc_fd, rbuf, hc->hc_io_size, MSG_DONTWAIT);
329   if (r == 0) {
330     errno = EIO;
331     return -1;
332   }
333   if (r < 0) {
334     if (ERRNO_AGAIN(errno)) {
335       http_client_poll_dir(hc, 1, 0);
336       errno = EAGAIN;
337       return r;
338     }
339     return r;
340   }
341   r2 = BIO_write(ssl->rbio, rbuf, r);
342   len = r - (r2 < 0 ? 0 : r2);
343   if (len) {
344     if (ssl->rbio_pos + len > ssl->rbio_size) {
345       ssl->rbio_buf = realloc(ssl->rbio_buf, ssl->rbio_pos + len);
346       ssl->rbio_size += len;
347     }
348     memcpy(ssl->rbio_buf + ssl->rbio_pos, rbuf + (len - r), len);
349     ssl->rbio_pos += len;
350   }
351   return 0;
352 }
353 
354 static int
http_client_ssl_write_update(http_client_t * hc)355 http_client_ssl_write_update( http_client_t *hc )
356 {
357   struct http_client_ssl *ssl = hc->hc_ssl;
358   char *rbuf = alloca(hc->hc_io_size);
359   ssize_t r, r2;
360   size_t len;
361 
362   if (ssl->wbio_pos) {
363     r = send(hc->hc_fd, ssl->wbio_buf, ssl->wbio_pos, MSG_DONTWAIT);
364     if (r > 0) {
365       memmove(ssl->wbio_buf, ssl->wbio_buf + r, ssl->wbio_pos - r);
366       ssl->wbio_pos -= r;
367     } else if (r < 0) {
368       if (ERRNO_AGAIN(errno)) {
369         http_client_poll_dir(hc, 0, 1);
370         errno = EAGAIN;
371         return r;
372       }
373       return r;
374     }
375     if (ssl->wbio_pos)
376       return 1;
377   }
378   r = BIO_read(ssl->wbio, rbuf, hc->hc_io_size);
379   if (r > 0) {
380     r2 = send(hc->hc_fd, rbuf, r, MSG_DONTWAIT);
381     len = r - (r2 < 0 ? 0 : r2);
382     if (len) {
383       if (ssl->wbio_pos + len > ssl->wbio_size) {
384         ssl->wbio_buf = realloc(ssl->wbio_buf, ssl->wbio_pos + len);
385         ssl->wbio_size += len;
386       }
387       memcpy(ssl->wbio_buf + ssl->wbio_pos, rbuf + (len - r), len);
388       ssl->wbio_pos += len;
389     }
390     if (r2 < 0) {
391       if (ERRNO_AGAIN(errno)) {
392         http_client_poll_dir(hc, 0, 1);
393         errno = EAGAIN;
394         return r2;
395       }
396       return r2;
397     }
398     return 1;
399   }
400   return 0;
401 }
402 
403 static ssize_t
http_client_ssl_recv(http_client_t * hc,void * buf,size_t len)404 http_client_ssl_recv( http_client_t *hc, void *buf, size_t len )
405 {
406   ssize_t r;
407   int e;
408 
409   while (1) {
410     r = SSL_read(hc->hc_ssl->ssl, buf, len);
411     if (r > 0)
412       return r;
413     e = SSL_get_error(hc->hc_ssl->ssl, r);
414     if (e == SSL_ERROR_WANT_READ) {
415       r = http_client_ssl_write_update(hc);
416       if (r < 0)
417         return r;
418       r = http_client_ssl_read_update(hc);
419       if (r < 0)
420         return r;
421     } else if (e == SSL_ERROR_WANT_WRITE) {
422       r = http_client_ssl_write_update(hc);
423       if (r < 0)
424         return r;
425     } else if (e == SSL_ERROR_ZERO_RETURN) {
426       errno = EIO;
427       return -1;
428     } else if (e == SSL_ERROR_WANT_CONNECT || e == SSL_ERROR_WANT_ACCEPT) {
429       errno = EBADF;
430       return -1;
431     } else if (e == SSL_ERROR_SSL) {
432       errno = EPERM;
433       return -1;
434     } else {
435       errno = EIO;
436       return -1;
437     }
438   }
439   return 0;
440 }
441 
442 static ssize_t
http_client_ssl_send(http_client_t * hc,const void * buf,size_t len)443 http_client_ssl_send( http_client_t *hc, const void *buf, size_t len )
444 {
445   struct http_client_ssl *ssl = hc->hc_ssl;
446   ssize_t r, r2;
447   int e;
448 
449   if (hc->hc_verify_peer < 0)
450     http_client_ssl_peer_verify(hc, 1); /* default method - verify */
451   while (1) {
452     if (!ssl->connected) {
453       r = SSL_connect(ssl->ssl);
454       if (r > 0) {
455         ssl->connected = 1;
456         if (hc->hc_verify_peer > 0) {
457           if (SSL_get_peer_certificate(ssl->ssl) == NULL ||
458               SSL_get_verify_result(ssl->ssl) != X509_V_OK) {
459             tvherror(LS_HTTPC, "%04X: SSL peer verification failed (%s:%i)%s %li",
460                    shortid(hc), hc->hc_host, hc->hc_port,
461                    SSL_get_peer_certificate(ssl->ssl) ? " X509" : "",
462                    SSL_get_verify_result(ssl->ssl));
463             errno = EPERM;
464             return -1;
465           }
466         }
467         goto write;
468       }
469     } else {
470 write:
471       r = SSL_write(ssl->ssl, buf, len);
472     }
473     if (r > 0) {
474       while (1) {
475         r2 = http_client_ssl_write_update(hc);
476         if (r2 < 0) {
477           if (ERRNO_AGAIN(errno))
478             break;
479           return r2;
480         }
481         if (r2 == 0)
482           break;
483       }
484       return r;
485     }
486     e = SSL_get_error(ssl->ssl, r);
487     ERR_print_errors_fp(stdout);
488     if (e == SSL_ERROR_WANT_READ) {
489       r = http_client_ssl_write_update(hc);
490       if (r < 0)
491         return r;
492       r = http_client_ssl_read_update(hc);
493       if (r < 0)
494         return r;
495     } else if (e == SSL_ERROR_WANT_WRITE) {
496       r = http_client_ssl_write_update(hc);
497       if (r < 0)
498         return r;
499     } else if (e == SSL_ERROR_WANT_CONNECT || e == SSL_ERROR_WANT_ACCEPT) {
500       errno = EBADF;
501       return -1;
502     } else if (e == SSL_ERROR_SSL) {
503       errno = EPERM;
504       return -1;
505     } else {
506       errno = EIO;
507       return -1;
508     }
509   }
510   return 0;
511 }
512 
513 static ssize_t
http_client_ssl_shutdown(http_client_t * hc)514 http_client_ssl_shutdown( http_client_t *hc )
515 {
516   ssize_t r;
517   int e;
518 
519   while (1) {
520     r = SSL_shutdown(hc->hc_ssl->ssl);
521     if (r > 0) {
522       /* everything done, bail-out completely */
523       http_client_shutdown(hc, 1, 0);
524       return r;
525     }
526     e = SSL_get_error(hc->hc_ssl->ssl, r);
527     if (e == SSL_ERROR_WANT_READ) {
528       r = http_client_ssl_write_update(hc);
529       if (r < 0)
530         return r;
531       r = http_client_ssl_read_update(hc);
532       if (r < 0)
533         return r;
534     } else if (e == SSL_ERROR_WANT_WRITE) {
535       r = http_client_ssl_write_update(hc);
536       if (r < 0)
537         return r;
538     } else if (e == SSL_ERROR_WANT_CONNECT || e == SSL_ERROR_WANT_ACCEPT) {
539       errno = EBADF;
540       return -1;
541     } else if (e == SSL_ERROR_SSL) {
542       errno = EPERM;
543       return -1;
544     } else {
545       errno = EIO;
546       return -1;
547     }
548   }
549   return 0;
550 }
551 
552 static int
http_client_send_partial(http_client_t * hc)553 http_client_send_partial( http_client_t *hc )
554 {
555   http_client_wcmd_t *wcmd;
556   ssize_t r;
557   int res = HTTP_CON_IDLE;
558 
559   wcmd = TAILQ_FIRST(&hc->hc_wqueue);
560   while (wcmd != NULL) {
561     hc->hc_cmd   = wcmd->wcmd;
562     hc->hc_rcseq = wcmd->wcseq;
563     if (hc->hc_einprogress && http_client_einprogress(hc)) {
564       errno = EINPROGRESS;
565       r = -1;
566       goto skip;
567     }
568     if (hc->hc_ssl)
569       r = http_client_ssl_send(hc, wcmd->wbuf + wcmd->wpos,
570                                wcmd->wsize - wcmd->wpos);
571     else
572       r = send(hc->hc_fd, wcmd->wbuf + wcmd->wpos,
573                wcmd->wsize - wcmd->wpos, MSG_DONTWAIT);
574 skip:
575     if (r < 0) {
576       if (ERRNO_AGAIN(errno) || errno == EINPROGRESS) {
577         http_client_direction(hc, 1);
578         return HTTP_CON_SENDING;
579       }
580       return http_client_flush(hc, -errno);
581     }
582     wcmd->wpos += r;
583     if (wcmd->wpos >= wcmd->wsize) {
584       res = HTTP_CON_SENT;
585       wcmd = NULL;
586     }
587     break;
588   }
589   if (wcmd == NULL) {
590     http_client_direction(hc, 0);
591     return res;
592   } else {
593     http_client_direction(hc, 1);
594     return HTTP_CON_SENDING;
595   }
596 }
597 
598 int
http_client_send(http_client_t * hc,enum http_cmd cmd,const char * path,const char * query,http_arg_list_t * header,void * body,size_t body_size)599 http_client_send( http_client_t *hc, enum http_cmd cmd,
600                   const char *path, const char *query,
601                   http_arg_list_t *header, void *body, size_t body_size )
602 {
603   http_client_wcmd_t *wcmd = calloc(1, sizeof(*wcmd));
604   http_arg_t *h;
605   htsbuf_queue_t q;
606   const char *s;
607   int empty;
608 
609   if (hc->hc_shutdown) {
610     if (header)
611       http_arg_flush(header);
612     free(wcmd);
613     return -EIO;
614   }
615 
616   wcmd->wcmd = cmd;
617   hc->hc_keepalive = 1;
618 
619   htsbuf_queue_init(&q, 0);
620   s = http_cmd2str(cmd);
621   if (s == NULL) {
622 error:
623     if (header)
624       http_arg_flush(header);
625     free(wcmd);
626     return -EINVAL;
627   }
628   htsbuf_append_str(&q, s);
629   htsbuf_append(&q, " ", 1);
630   if (tvh_str_default(path, NULL) == NULL)
631     path = "/";
632   htsbuf_append_str(&q, path);
633   if (query && query[0] != '\0') {
634     htsbuf_append(&q, "?", 1);
635     htsbuf_append_str(&q, query);
636   }
637   htsbuf_append(&q, " ", 1);
638   s = http_ver2str(hc->hc_version);
639   if (s == NULL) {
640     htsbuf_queue_flush(&q);
641     goto error;
642   }
643   htsbuf_append_str(&q, s);
644   htsbuf_append(&q, "\r\n", 2);
645 
646   if (header) {
647     TAILQ_FOREACH(h, header, link) {
648       htsbuf_append_str(&q, h->key);
649       htsbuf_append(&q, ": ", 2);
650       if (h->val)
651         htsbuf_append_str(&q, h->val);
652       htsbuf_append(&q, "\r\n", 2);
653       if (strcasecmp(h->key, "Connection") == 0 &&
654           strcasecmp(h->val ?: "", "close") == 0)
655         hc->hc_keepalive = 0;
656     }
657     http_arg_flush(header);
658   }
659 
660   if (hc->hc_version == HTTP_VERSION_1_0)
661     hc->hc_keepalive = 0;
662   if (hc->hc_version == RTSP_VERSION_1_0) {
663     hc->hc_cseq = (hc->hc_cseq + 1) & 0x7fff;
664     htsbuf_qprintf(&q, "CSeq: %i\r\n", hc->hc_cseq);
665     wcmd->wcseq = hc->hc_cseq;
666   }
667   htsbuf_append(&q, "\r\n", 2);
668   if (body && body_size)
669     htsbuf_append(&q, body, body_size);
670 
671   body_size = q.hq_size;
672   body = malloc(body_size);
673   htsbuf_read(&q, body, body_size);
674 
675   if (tvhtrace_enabled()) {
676     tvhtrace(LS_HTTPC, "%04X: sending %s cmd", shortid(hc), http_ver2str(hc->hc_version));
677     tvhlog_hexdump(LS_HTTPC, body, body_size);
678   }
679 
680   wcmd->wbuf  = body;
681   wcmd->wsize = body_size;
682 
683   empty = TAILQ_EMPTY(&hc->hc_wqueue);
684   TAILQ_INSERT_TAIL(&hc->hc_wqueue, wcmd, link);
685 
686   hc->hc_ping_time = mclk();
687 
688   if (empty)
689     return http_client_send_partial(hc);
690   return HTTP_CON_SENDING;
691 }
692 
693 static int
http_client_finish(http_client_t * hc)694 http_client_finish( http_client_t *hc )
695 {
696   http_client_wcmd_t *wcmd;
697   int res;
698 
699   tvhtrace(LS_HTTPC, "%04X: finishing", shortid(hc));
700 
701   assert(!hc->hc_in_rtp_data);
702 
703   if (hc->hc_data_complete) {
704     http_client_get(hc);
705     pthread_mutex_unlock(&hc->hc_mutex);
706     res = hc->hc_data_complete(hc);
707     pthread_mutex_lock(&hc->hc_mutex);
708     http_client_put(hc);
709     if (res < 0)
710       return http_client_flush(hc, res);
711   }
712   hc->hc_hsize = hc->hc_csize = 0;
713   wcmd = TAILQ_FIRST(&hc->hc_wqueue);
714   if (wcmd)
715     http_client_cmd_destroy(hc, wcmd);
716   if (hc->hc_version != RTSP_VERSION_1_0 &&
717       hc->hc_handle_location &&
718       (hc->hc_code == HTTP_STATUS_MOVED ||
719        hc->hc_code == HTTP_STATUS_FOUND ||
720        hc->hc_code == HTTP_STATUS_SEE_OTHER ||
721        hc->hc_code == HTTP_STATUS_NOT_MODIFIED)) {
722     const char *p = http_arg_get(&hc->hc_args, "Location");
723     if (p) {
724       hc->hc_location = strdup(p);
725       res = http_client_redirected(hc);
726       if (res < 0)
727         return http_client_flush(hc, res);
728       return HTTP_CON_RECEIVING;
729     }
730   }
731   if (TAILQ_FIRST(&hc->hc_wqueue) && hc->hc_code == HTTP_STATUS_OK) {
732     hc->hc_code = 0;
733     return http_client_send_partial(hc);
734   }
735   if (!hc->hc_keepalive) {
736     http_client_shutdown(hc, 0, 0);
737     if (hc->hc_ssl) {
738       /* finish the shutdown I/O sequence, notify owner later */
739       errno = EAGAIN;
740       return HTTP_CON_RECEIVING;
741     }
742   }
743   return hc->hc_reconnected ? HTTP_CON_RECEIVING : HTTP_CON_DONE;
744 }
745 
746 static int
http_client_parse_arg(http_arg_list_t * list,const char * p)747 http_client_parse_arg( http_arg_list_t *list, const char *p )
748 {
749   char *d, *t;
750 
751   d = strchr(p, ':');
752   if (d) {
753     *d++ = '\0';
754     while (*d && *d <= ' ')
755       d++;
756     t = d + strlen(d);
757     while (--t != d && *t <= ' ')
758       *t = '\0';
759     http_arg_set(list, p, d);
760     return 0;
761   }
762   return -EINVAL;
763 }
764 
765 static int
http_client_data_copy(http_client_t * hc,char * buf,size_t len)766 http_client_data_copy( http_client_t *hc, char *buf, size_t len )
767 {
768   int res;
769 
770   if (hc->hc_data_received) {
771     http_client_get(hc);
772     pthread_mutex_unlock(&hc->hc_mutex);
773     res = hc->hc_data_received(hc, buf, len);
774     pthread_mutex_lock(&hc->hc_mutex);
775     http_client_put(hc);
776     if (res < 0)
777       return res;
778   } else {
779     hc->hc_data = realloc(hc->hc_data, hc->hc_data_size + len + 1);
780     memcpy(hc->hc_data + hc->hc_data_size, buf, len);
781     hc->hc_data_size += len;
782     hc->hc_data[hc->hc_data_size] = '\0';
783   }
784   return 0;
785 }
786 
787 static ssize_t
http_client_data_chunked(http_client_t * hc,char * buf,size_t len,int * end)788 http_client_data_chunked( http_client_t *hc, char *buf, size_t len, int *end )
789 {
790   size_t old = len, l, l2;
791   char *d, *s;
792   int res;
793 
794   while (len > 0) {
795     if (hc->hc_chunk_size) {
796       s = hc->hc_chunk;
797       l = len;
798       if (hc->hc_chunk_pos + l > hc->hc_chunk_size)
799         l = hc->hc_chunk_size - hc->hc_chunk_pos;
800       memcpy(s + hc->hc_chunk_pos, buf, l);
801       hc->hc_chunk_pos += l;
802       buf += l;
803       len -= l;
804       if (hc->hc_chunk_pos >= hc->hc_chunk_size) {
805         if (s[hc->hc_chunk_size - 2] != '\r' &&
806             s[hc->hc_chunk_size - 1] != '\n')
807           return -EIO;
808         res = http_client_data_copy(hc, hc->hc_chunk, hc->hc_chunk_size - 2);
809         if (res < 0)
810           return res;
811         hc->hc_chunk_size = hc->hc_chunk_pos = 0;
812       }
813       continue;
814     }
815     l = 0;
816     if (hc->hc_chunk_csize) {
817       s = hc->hc_chunk;
818       if (buf[0] == '\n' && s[hc->hc_chunk_csize-1] == '\r')
819         l = 1;
820       else if (len > 1 && buf[0] == '\r' && buf[1] == '\n')
821         l = 2;
822     } else {
823       d = strstr(s = buf, "\r\n");
824       if (d) {
825         *d = '\0';
826         l = (d + 2) - s;
827       }
828     }
829     if (l) {
830       hc->hc_chunk_csize = 0;
831       if (hc->hc_chunk_trails) {
832         buf += l;
833         len -= l;
834         if (s[0] == '\0') {
835           *end = 1;
836           return old - len;
837         }
838         res = http_client_parse_arg(&hc->hc_args, s);
839         if (res < 0)
840           return res;
841         continue;
842       }
843       d = s + 1;
844       while (*d == '0' && *d)
845         d++;
846       if (s[0] == '0' && *d == '\0')
847         hc->hc_chunk_trails = 1;
848       else {
849         hc->hc_chunk_size = strtoll(s, NULL, 16);
850         if (hc->hc_chunk_size == 0)
851           return -EIO;
852         if (hc->hc_chunk_size > 256*1024)
853           return -EMSGSIZE;
854         hc->hc_chunk_size += 2; /* CR-LF */
855         if (hc->hc_chunk_alloc < hc->hc_chunk_size) {
856           hc->hc_chunk = realloc(hc->hc_chunk, hc->hc_chunk_size + 1);
857           hc->hc_chunk[hc->hc_chunk_size] = '\0';
858           hc->hc_chunk_alloc = hc->hc_chunk_size;
859         }
860       }
861       buf += l;
862       len -= l;
863     } else {
864       l2 = hc->hc_chunk_csize + len;
865       if (l2 > hc->hc_chunk_alloc) {
866         hc->hc_chunk = realloc(hc->hc_chunk, l2 + 1);
867         hc->hc_chunk[l2] = '\0';
868         hc->hc_chunk_alloc = l2;
869       }
870       memcpy(hc->hc_chunk + hc->hc_chunk_csize, buf, len);
871       hc->hc_chunk_csize += len;
872       buf += len;
873       len -= len;
874     }
875   }
876   return old;
877 }
878 
879 static int
http_client_data_received(http_client_t * hc,char * buf,ssize_t len,int hdr)880 http_client_data_received( http_client_t *hc, char *buf, ssize_t len, int hdr )
881 {
882   ssize_t l, l2, csize;
883   int res, end = 0;
884 
885   buf[len] = '\0';
886 
887   if (len == 0) {
888     if (hc->hc_csize == -1)
889       return 1;
890     if (!hdr && hc->hc_rpos >= hc->hc_csize)
891       return 1;
892     return 0;
893   }
894 
895   csize = hc->hc_csize == (size_t)-1 ? 0 : hc->hc_csize;
896   l = len;
897   if (hc->hc_csize && hc->hc_csize != (size_t)-1 && hc->hc_rpos > csize) {
898     l2 = hc->hc_rpos - csize;
899     if (l2 < l)
900       l = l2;
901   }
902   if (l) {
903     if (hc->hc_chunked) {
904       l = http_client_data_chunked(hc, buf, l, &end);
905       if (l < 0)
906         return l;
907     } else {
908       res = http_client_data_copy(hc, buf, l);
909       if (res < 0)
910         return res;
911     }
912   }
913   hc->hc_rpos += l;
914   if (hc->hc_csize && hc->hc_rpos >= hc->hc_csize) {
915     end = 1;
916     hc->hc_rpos = 0;
917     hc->hc_in_data = 0;
918   } else if (end) {
919     hc->hc_in_data = 0;
920   }
921   if (l < len) {
922     l2 = len - l;
923     if (l2 + 1 > hc->hc_rsize)
924       hc->hc_rbuf = realloc(hc->hc_rbuf, hc->hc_rsize = l2 + 1);
925     memcpy(hc->hc_rbuf, buf + l, l2);
926     hc->hc_rbuf[l2] = '\0';
927     hc->hc_rpos = l2;
928   }
929   return end ? 1 : 0;
930 }
931 
932 static int
http_client_run0(http_client_t * hc)933 http_client_run0( http_client_t *hc )
934 {
935   char *buf, *saveptr, *argv[3], *d, *p;
936   int ver, res, delimsize;
937   ssize_t r;
938   size_t len;
939 
940   if (hc->hc_shutdown) {
941     if (hc->hc_ssl && hc->hc_ssl->shutdown) {
942       r = http_client_ssl_shutdown(hc);
943       if (r < 0) {
944         if (errno != EIO) {
945           if (ERRNO_AGAIN(errno))
946             return HTTP_CON_SENDING;
947           return r;
948         }
949       }
950       if (r == 0)
951         return HTTP_CON_SENDING;
952     }
953     return hc->hc_result ? hc->hc_result : HTTP_CON_DONE;
954   }
955 
956   if (hc->hc_sending) {
957     res = http_client_send_partial(hc);
958     if (res < 0 || res == HTTP_CON_SENDING)
959       return res;
960   }
961 
962   buf = alloca(hc->hc_io_size + 1);
963   if (!hc->hc_in_data && !hc->hc_in_rtp_data && hc->hc_rpos > 3) {
964     hc->hc_rbuf[hc->hc_rpos] = '\0';
965     if (hc->hc_version == RTSP_VERSION_1_0 && hc->hc_rbuf[0] == '$')
966       goto rtsp_data;
967     else if ((d = strstr(hc->hc_rbuf, "\r\n\r\n")) != NULL) {
968       delimsize = 4;
969       goto header;
970     }
971     if ((d = strstr(hc->hc_rbuf, "\n\n")) != NULL) {
972       delimsize = 2;
973       goto header;
974     }
975   }
976 
977 retry:
978   if (hc->hc_pause) {
979     http_client_poll_dir(hc, 0, 0);
980     return HTTP_CON_RECEIVING;
981   }
982   if (hc->hc_ssl)
983     r = http_client_ssl_recv(hc, buf, hc->hc_io_size);
984   else
985     r = recv(hc->hc_fd, buf, hc->hc_io_size, MSG_DONTWAIT);
986   if (r == 0) {
987     tvhtrace(LS_HTTPC, "%04X: end of stream", shortid(hc));
988     if (hc->hc_in_data && !hc->hc_keepalive) {
989       tvhtrace(LS_HTTPC, "%04X: no keep-alive, finishing", shortid(hc));
990       return http_client_finish(hc);
991     }
992     return http_client_flush(hc, -EIO);
993   }
994   if (r < 0) {
995     if (errno == EIO && hc->hc_in_data && !hc->hc_keepalive) {
996       tvhtrace(LS_HTTPC, "%04X: error reading: %s", shortid(hc), strerror(errno));
997       tvhtrace(LS_HTTPC, "%04X: no keep-alive, finishing", shortid(hc));
998       return http_client_finish(hc);
999     }
1000     if (ERRNO_AGAIN(errno))
1001       return HTTP_CON_RECEIVING;
1002     tvhtrace(LS_HTTPC, "%04X: error reading: %s", shortid(hc), strerror(errno));
1003     return http_client_flush(hc, -errno);
1004   }
1005 
1006   if (hc->hc_in_data && !hc->hc_in_rtp_data) {
1007     res = http_client_data_received(hc, buf, r, 0);
1008     if (res < 0)
1009       return http_client_flush(hc, res);
1010     if (res > 0) {
1011       tvhtrace(LS_HTTPC, "%04X: data complete, finishing", shortid(hc));
1012       return http_client_finish(hc);
1013     }
1014     if (hc->hc_data_limit && r + hc->hc_rsize >= hc->hc_data_limit) {
1015       tvhtrace(LS_HTTPC, "%04X: data overflow", shortid(hc));
1016       return http_client_flush(hc, -EOVERFLOW);
1017     }
1018     goto retry;
1019   }
1020 
1021   if (hc->hc_rsize < r + hc->hc_rpos) {
1022     if (hc->hc_rpos + r > hc->hc_io_size + 20*1024) {
1023       tvhtrace(LS_HTTPC, "%04X: overflow, buf %zd pos %zd read %zd io %zd",
1024                shortid(hc), hc->hc_rsize, hc->hc_rpos, r, hc->hc_io_size);
1025       return http_client_flush(hc, -EMSGSIZE);
1026     }
1027     hc->hc_rsize += hc->hc_rpos + r + 4*1024;
1028     hc->hc_rbuf = realloc(hc->hc_rbuf, hc->hc_rsize + 1);
1029   }
1030   memcpy(hc->hc_rbuf + hc->hc_rpos, buf, r);
1031   hc->hc_rpos += r;
1032 
1033 next_header:
1034   if (hc->hc_rpos < 3)
1035     return HTTP_CON_RECEIVING;
1036   if (hc->hc_version == RTSP_VERSION_1_0 && hc->hc_rbuf[0] == '$')
1037     goto rtsp_data;
1038   hc->hc_rbuf[hc->hc_rpos] = '\0';
1039   delimsize = 4;
1040   if ((d = strstr(hc->hc_rbuf, "\r\n\r\n")) == NULL) {
1041     delimsize = 2;
1042     if ((d = strstr(hc->hc_rbuf, "\n\n")) == NULL)
1043       return HTTP_CON_RECEIVING;
1044   }
1045 
1046 header:
1047   *d = '\0';
1048   len = hc->hc_rpos;
1049   hc->hc_reconnected = 0;
1050   http_client_clear_state(hc);
1051   hc->hc_rpos  = len;
1052   hc->hc_hsize = d - hc->hc_rbuf + delimsize;
1053   p = strtok_r(hc->hc_rbuf, "\r\n", &saveptr);
1054   if (p == NULL)
1055     return http_client_flush(hc, -EINVAL);
1056   tvhtrace(LS_HTTPC, "%04X: %s answer '%s' (rcseq: %d)",
1057            shortid(hc), http_ver2str(hc->hc_version), p, hc->hc_rcseq);
1058   tvhlog_hexdump(LS_HTTPC, hc->hc_rbuf, hc->hc_hsize);
1059   if (http_tokenize(p, argv, 3, -1) != 3)
1060     return http_client_flush(hc, -EINVAL);
1061   if ((ver = http_str2ver(argv[0])) < 0)
1062     return http_client_flush(hc, -EINVAL);
1063   if (ver != hc->hc_version) {
1064     /* 1.1 -> 1.0 transition allowed */
1065     if (hc->hc_version == HTTP_VERSION_1_1 && ver == HTTP_VERSION_1_0)
1066       hc->hc_version = ver;
1067     else
1068       return http_client_flush(hc, -EINVAL);
1069   }
1070   if ((hc->hc_code = atoi(argv[1])) < 200)
1071     return http_client_flush(hc, -EINVAL);
1072   while ((p = strtok_r(NULL, "\r\n", &saveptr)) != NULL) {
1073     res = http_client_parse_arg(&hc->hc_args, p);
1074     if (res < 0)
1075       return http_client_flush(hc, -EINVAL);
1076   }
1077   p = http_arg_get(&hc->hc_args, "Content-Length");
1078   if (p) {
1079     hc->hc_csize = atoll(p);
1080     if (hc->hc_csize == 0)
1081       hc->hc_csize = -1;
1082   }
1083   p = http_arg_get(&hc->hc_args, "Connection");
1084   if (p && ver != RTSP_VERSION_1_0) {
1085     if (strcasecmp(p, "close") == 0)
1086       hc->hc_keepalive = 0;
1087     else if (strcasecmp(p, "keep-alive")) /* no change for keep-alive */
1088       return http_client_flush(hc, -EINVAL);
1089   }
1090   if (ver == RTSP_VERSION_1_0) {
1091     p = http_arg_get(&hc->hc_args, "CSeq");
1092     if (p == NULL || hc->hc_rcseq != atoi(p))
1093       return http_client_flush(hc, -EINVAL);
1094   }
1095   p = http_arg_get(&hc->hc_args, "Transfer-Encoding");
1096   if (p)
1097     hc->hc_chunked = strcasecmp(p, "chunked") == 0;
1098   if (hc->hc_hdr_received) {
1099     http_client_get(hc);
1100     pthread_mutex_unlock(&hc->hc_mutex);
1101     res = hc->hc_hdr_received(hc);
1102     pthread_mutex_lock(&hc->hc_mutex);
1103     http_client_put(hc);
1104     if (res < 0)
1105       return http_client_flush(hc, res);
1106   }
1107   if (hc->hc_code == HTTP_STATUS_CONTINUE) {
1108     http_client_rbuf_cut(hc, hc->hc_hsize);
1109     goto next_header;
1110   }
1111   if (hc->hc_version == RTSP_VERSION_1_0 &&
1112      (hc->hc_csize == -1 || !hc->hc_csize)) {
1113     hc->hc_csize = -1;
1114     hc->hc_in_data = 0;
1115     http_client_rbuf_cut(hc, hc->hc_hsize);
1116     return http_client_finish(hc);
1117   } else {
1118     hc->hc_in_data = 1;
1119   }
1120   len = hc->hc_rpos - hc->hc_hsize;
1121   hc->hc_rpos = 0;
1122   res = http_client_data_received(hc, hc->hc_rbuf + hc->hc_hsize, len, 1);
1123   if (res < 0)
1124     return http_client_flush(hc, res);
1125   if (res > 0)
1126     return http_client_finish(hc);
1127   goto retry;
1128 
1129 rtsp_data:
1130   /* RTSP embedded data */
1131   r = 0;
1132   hc->hc_in_data = 0;
1133   hc->hc_in_rtp_data = 0;
1134   while (hc->hc_rpos > r + 3) {
1135     if (hc->hc_rbuf[r] != '$')
1136       break;
1137     hc->hc_csize = 4 + ((hc->hc_rbuf[r+2] << 8) | hc->hc_rbuf[r+3]);
1138     hc->hc_chunked = 0;
1139     if (r + hc->hc_csize > hc->hc_rpos) {
1140       http_client_rbuf_cut(hc, r);
1141       hc->hc_in_rtp_data = 1;
1142       if (r == 0)
1143         goto retry;
1144       return HTTP_CON_RECEIVING;
1145     }
1146     if (hc->hc_rtp_data_received) {
1147       http_client_get(hc);
1148       pthread_mutex_unlock(&hc->hc_mutex);
1149       res = hc->hc_rtp_data_received(hc, hc->hc_rbuf + r, hc->hc_csize);
1150       pthread_mutex_lock(&hc->hc_mutex);
1151       http_client_put(hc);
1152       if (res < 0)
1153         return res;
1154     }
1155     r += hc->hc_csize;
1156     hc->hc_code = 0;
1157     res = 0;
1158     if (hc->hc_rtp_data_complete) {
1159       http_client_get(hc);
1160       pthread_mutex_unlock(&hc->hc_mutex);
1161       res = hc->hc_rtp_data_complete(hc);
1162       pthread_mutex_lock(&hc->hc_mutex);
1163       http_client_put(hc);
1164     }
1165     hc->hc_in_rtp_data = 0;
1166     if (res < 0)
1167       return http_client_flush(hc, res);
1168   }
1169   if (r > 0) {
1170     http_client_rbuf_cut(hc, r);
1171     goto next_header;
1172   }
1173   return HTTP_CON_RECEIVING;
1174 }
1175 
1176 int
http_client_run(http_client_t * hc)1177 http_client_run( http_client_t *hc )
1178 {
1179   int r;
1180 
1181   if (hc == NULL)
1182     return 0;
1183   pthread_mutex_lock(&hc->hc_mutex);
1184   r = http_client_run0(hc);
1185   pthread_mutex_unlock(&hc->hc_mutex);
1186   return r;
1187 }
1188 
1189 /*
1190  *
1191  */
1192 void
http_client_basic_auth(http_client_t * hc,http_arg_list_t * h,const char * user,const char * pass)1193 http_client_basic_auth( http_client_t *hc, http_arg_list_t *h,
1194                         const char *user, const char *pass )
1195 {
1196   if (user && user[0] && pass && pass[0]) {
1197 #define BASIC "Basic "
1198     size_t plen = strlen(pass);
1199     size_t ulen = strlen(user);
1200     size_t len = BASE64_SIZE(plen + ulen + 1) + 1;
1201     char *buf = alloca(ulen + 1 + plen + 1);
1202     char *cbuf = alloca(len + sizeof(BASIC) + 1);
1203     strcpy(buf, user);
1204     strcat(buf, ":");
1205     strcat(buf, pass);
1206     strcpy(cbuf, BASIC);
1207     base64_encode(cbuf + sizeof(BASIC) - 1, len,
1208                   (uint8_t *)buf, ulen + 1 + plen);
1209     http_arg_set(h, "Authorization", cbuf);
1210 #undef BASIC
1211   }
1212 }
1213 
1214 /*
1215  * Redirected
1216  */
1217 void
http_client_basic_args(http_client_t * hc,http_arg_list_t * h,const url_t * url,int keepalive)1218 http_client_basic_args ( http_client_t *hc, http_arg_list_t *h, const url_t *url, int keepalive )
1219 {
1220   char buf[256];
1221 
1222   http_arg_flush(h);
1223   if (url->port == 0) { /* default port */
1224     http_arg_set(h, "Host", url->host);
1225   } else {
1226     snprintf(buf, sizeof(buf), "%s:%u", url->host,
1227                                         http_port(hc, url->scheme, url->port));
1228     http_arg_set(h, "Host", buf);
1229   }
1230   if (http_user_agent) {
1231     http_arg_set(h, "User-Agent", http_user_agent);
1232   } else {
1233     snprintf(buf, sizeof(buf), "TVHeadend/%s", tvheadend_version);
1234     http_arg_set(h, "User-Agent", buf);
1235   }
1236   if (!keepalive)
1237     http_arg_set(h, "Connection", "close");
1238   http_client_basic_auth(hc, h, url->user, url->pass);
1239 }
1240 
1241 static char *
strstrip(char * s)1242 strstrip(char *s)
1243 {
1244   size_t l;
1245   if (s != NULL) {
1246     while (*s && *s <= ' ') s++;
1247     l = *s ? 0 : strlen(s) - 1;
1248     while (*s && s[l] <= ' ') s[l--] = '\0';
1249   }
1250   return s;
1251 }
1252 
1253 void
http_client_add_args(http_client_t * hc,http_arg_list_t * h,const char * args)1254 http_client_add_args ( http_client_t *hc, http_arg_list_t *h, const char *args )
1255 {
1256   char *p, *k, *v;
1257 
1258   if (args == NULL)
1259     return;
1260   p = tvh_strdupa(args);
1261   while (*p) {
1262     while (*p && *p <= ' ') p++;
1263     if (*p == '\0') break;
1264     k = p;
1265     while (*p && *p != '\r' && *p != '\n' && *p != ':' && *p != '=') p++;
1266     v = NULL;
1267     if (*p == '=' || *p == ':') { *p = '\0'; p++; v = p; }
1268     while (*p && *p != '\r' && *p != '\n') p++;
1269     if (*p) { *p = '\0'; p++; }
1270     k = strstrip(k);
1271     v = strstrip(v);
1272     if (v && *v && *k &&
1273         strcasecmp(k, "Connection") != 0 &&
1274         strcasecmp(k, "Host") != 0) {
1275       http_arg_get_remove(h, k);
1276       http_arg_set(h, k, v);
1277     }
1278   }
1279 }
1280 
1281 int
http_client_simple_reconnect(http_client_t * hc,const url_t * u,http_ver_t ver)1282 http_client_simple_reconnect ( http_client_t *hc, const url_t *u,
1283                                http_ver_t ver )
1284 {
1285   http_arg_list_t h;
1286   tvhpoll_t *efd;
1287   int r;
1288 
1289   lock_assert(&hc->hc_mutex);
1290 
1291   if (tvh_str_default(u->scheme, NULL) == NULL ||
1292       tvh_str_default(u->host, NULL) == NULL ||
1293       u->port < 0) {
1294     tvherror(LS_HTTPC, "Invalid url '%s'", u->raw);
1295     return -EINVAL;
1296   }
1297   if (strcmp(u->scheme, hc->hc_scheme) ||
1298       strcmp(u->host, hc->hc_host) ||
1299       http_port(hc, u->scheme, u->port) != hc->hc_port ||
1300       !hc->hc_keepalive) {
1301     efd = hc->hc_efd;
1302     http_client_shutdown(hc, 1, 1);
1303     r = http_client_reconnect(hc, hc->hc_version,
1304                               u->scheme, u->host, u->port);
1305     hc->hc_efd = efd;
1306     if (r < 0)
1307       return r;
1308     r = hc->hc_verify_peer;
1309     hc->hc_verify_peer = -1;
1310     http_client_ssl_peer_verify(hc, r);
1311   }
1312 
1313   http_client_flush(hc, 0);
1314 
1315   http_arg_init(&h);
1316   hc->hc_hdr_create(hc, &h, u, 0);
1317   hc->hc_reconnected = 1;
1318   hc->hc_shutdown    = 0;
1319   hc->hc_pevents     = 0;
1320   hc->hc_version     = ver;
1321 
1322   r = http_client_send(hc, hc->hc_cmd, u->path, u->query, &h, NULL, 0);
1323   if (r < 0)
1324     return r;
1325 
1326   hc->hc_reconnected = 1;
1327   free(hc->hc_url);
1328   hc->hc_url = u->raw ? strdup(u->raw) : NULL;
1329   return HTTP_CON_RECEIVING;
1330 }
1331 
1332 static int
http_client_redirected(http_client_t * hc)1333 http_client_redirected ( http_client_t *hc )
1334 {
1335   char *location, *location2;
1336   url_t u;
1337   int r;
1338 
1339   if (++hc->hc_redirects > 10)
1340     return -ELOOP;
1341 
1342   location  = hc->hc_location;
1343   location2 = hc->hc_location = NULL;
1344 
1345   if (location[0] == '\0' || location[0] == '/') {
1346     size_t size2 = strlen(hc->hc_scheme) + 3 + strlen(hc->hc_host) +
1347                    12 + strlen(location) + 1;
1348     location2 = alloca(size2);
1349     snprintf(location2, size2, "%s://%s:%i%s",
1350         hc->hc_scheme, hc->hc_host, hc->hc_port, location);
1351   }
1352 
1353   urlinit(&u);
1354   if (urlparse(location2 ? location2 : location, &u)) {
1355     tvherror(LS_HTTPC, "%04X: redirection - cannot parse url '%s'",
1356              shortid(hc), location2 ? location2 : location);
1357     free(location);
1358     return -EIO;
1359   }
1360   free(location);
1361 
1362   r = http_client_simple_reconnect(hc, &u, hc->hc_redirv);
1363 
1364   urlreset(&u);
1365   return r;
1366 }
1367 
1368 int
http_client_simple(http_client_t * hc,const url_t * url)1369 http_client_simple( http_client_t *hc, const url_t *url )
1370 {
1371   http_arg_list_t h;
1372   int r;
1373 
1374   pthread_mutex_lock(&hc->hc_mutex);
1375   http_arg_init(&h);
1376   hc->hc_hdr_create(hc, &h, url, 0);
1377   free(hc->hc_url);
1378   hc->hc_url = url->raw ? strdup(url->raw) : NULL;
1379   r = http_client_send(hc, HTTP_CMD_GET, url->path, url->query,
1380                        &h, NULL, 0);
1381   pthread_mutex_unlock(&hc->hc_mutex);
1382   return r;
1383 }
1384 
1385 void
http_client_ssl_peer_verify(http_client_t * hc,int verify)1386 http_client_ssl_peer_verify( http_client_t *hc, int verify )
1387 {
1388   struct http_client_ssl *ssl;
1389 
1390   if (hc->hc_verify_peer < 0) {
1391     hc->hc_verify_peer = verify ? 1 : 0;
1392     if ((ssl = hc->hc_ssl) != NULL) {
1393       if (!SSL_CTX_set_default_verify_paths(ssl->ctx))
1394         tvherror(LS_HTTPC, "%04X: SSL - unable to load CA certificates for verification", shortid(hc));
1395       SSL_CTX_set_verify_depth(ssl->ctx, 1);
1396       SSL_CTX_set_verify(ssl->ctx,
1397                          hc->hc_verify_peer ? SSL_VERIFY_PEER : SSL_VERIFY_NONE,
1398                          NULL);
1399     }
1400   } else {
1401     tvherror(LS_HTTPC, "%04X: SSL peer verification method must be set only once", shortid(hc));
1402   }
1403 }
1404 
1405 /*
1406  * Data thread
1407  */
1408 static void *
http_client_thread(void * p)1409 http_client_thread ( void *p )
1410 {
1411   int n;
1412   tvhpoll_event_t ev;
1413   http_client_t *hc;
1414   char c;
1415 
1416   while (atomic_get(&http_running)) {
1417     n = tvhpoll_wait(http_poll, &ev, 1, -1);
1418     if (n < 0) {
1419       if (atomic_get(&http_running) && !ERRNO_AGAIN(errno))
1420         tvherror(LS_HTTPC, "tvhpoll_wait() error");
1421     } else if (n > 0) {
1422       if (&http_pipe == ev.data.ptr) {
1423         if (read(http_pipe.rd, &c, 1) == 1) {
1424           /* end-of-task */
1425           break;
1426         }
1427         continue;
1428       }
1429       pthread_mutex_lock(&http_lock);
1430       TAILQ_FOREACH(hc, &http_clients, hc_link)
1431         if (hc == ev.data.ptr)
1432           break;
1433       if (hc == NULL) {
1434         pthread_mutex_unlock(&http_lock);
1435         continue;
1436       }
1437       if (hc->hc_shutdown_wait) {
1438         tvh_cond_signal(&http_cond, 1);
1439         /* Disable the poll looping for this moment */
1440         http_client_poll_dir(hc, 0, 0);
1441         pthread_mutex_unlock(&http_lock);
1442         continue;
1443       }
1444       hc->hc_running = 1;
1445       pthread_mutex_unlock(&http_lock);
1446       http_client_run(hc);
1447       pthread_mutex_lock(&http_lock);
1448       hc->hc_running = 0;
1449       if (hc->hc_shutdown_wait)
1450         tvh_cond_signal(&http_cond, 1);
1451       pthread_mutex_unlock(&http_lock);
1452     }
1453   }
1454 
1455   return NULL;
1456 }
1457 
1458 static void
http_client_ssl_free(http_client_t * hc)1459 http_client_ssl_free( http_client_t *hc )
1460 {
1461   struct http_client_ssl *ssl;
1462 
1463   if ((ssl = hc->hc_ssl) != NULL) {
1464     free(ssl->rbio_buf);
1465     free(ssl->wbio_buf);
1466     SSL_free(ssl->ssl);
1467     SSL_CTX_free(ssl->ctx);
1468     free(ssl);
1469     hc->hc_ssl = NULL;
1470   }
1471 }
1472 
1473 /*
1474  * Setup a connection (async)
1475  */
1476 static int
http_client_reconnect(http_client_t * hc,http_ver_t ver,const char * scheme,const char * host,int port)1477 http_client_reconnect
1478   ( http_client_t *hc, http_ver_t ver, const char *scheme,
1479     const char *host, int port )
1480 {
1481   struct http_client_ssl *ssl;
1482   char errbuf[256];
1483 
1484   free(hc->hc_scheme);
1485   free(hc->hc_host);
1486 
1487   if (scheme == NULL || host == NULL)
1488     goto errnval;
1489 
1490   port           = http_port(hc, scheme, port);
1491   hc->hc_pevents = 0;
1492   hc->hc_version = ver;
1493   hc->hc_redirv  = ver;
1494   hc->hc_scheme  = strdup(scheme);
1495   hc->hc_host    = strdup(host);
1496   hc->hc_port    = port;
1497   hc->hc_fd      = tcp_connect(host, port, hc->hc_bindaddr, errbuf, sizeof(errbuf), -1);
1498   if (hc->hc_fd < 0) {
1499     tvherror(LS_HTTPC, "%04X: Unable to connect to %s:%i - %s", shortid(hc), host, port, errbuf);
1500     goto errnval;
1501   }
1502   hc->hc_einprogress = 1;
1503   tvhtrace(LS_HTTPC, "%04X: Connected to %s:%i", shortid(hc), host, port);
1504   http_client_ssl_free(hc);
1505   if (strcasecmp(scheme, "https") == 0 || strcasecmp(scheme, "rtsps") == 0) {
1506     ssl = calloc(1, sizeof(*ssl));
1507     hc->hc_ssl = ssl;
1508     ssl->ctx   = SSL_CTX_new(SSLv23_client_method());
1509     if (ssl->ctx == NULL) {
1510       tvherror(LS_HTTPC, "%04X: Unable to get SSL_CTX", shortid(hc));
1511       goto err1;
1512     }
1513     /* do not use SSLv2 */
1514     SSL_CTX_set_options(ssl->ctx, SSL_OP_NO_SSLv2 | SSL_OP_NO_COMPRESSION);
1515     /* adjust cipher list */
1516     if (SSL_CTX_set_cipher_list(ssl->ctx, "HIGH:MEDIUM") != 1) {
1517       tvherror(LS_HTTPC, "%04X: Unable to adjust SSL cipher list", shortid(hc));
1518       goto err2;
1519     }
1520     ssl->rbio  = BIO_new(BIO_s_mem());
1521     ssl->wbio  = BIO_new(BIO_s_mem());
1522     ssl->ssl   = SSL_new(ssl->ctx);
1523     if (ssl->ssl == NULL || ssl->rbio == NULL || ssl->wbio == NULL) {
1524       tvherror(LS_HTTPC, "%04X: Unable to get SSL handle", shortid(hc));
1525       goto err3;
1526     }
1527     SSL_set_bio(ssl->ssl, ssl->rbio, ssl->wbio);
1528     if (!SSL_set_tlsext_host_name(ssl->ssl, host)) {
1529       tvherror(LS_HTTPC, "%04X: Unable to set SSL hostname", shortid(hc));
1530       goto err4;
1531     }
1532   }
1533 
1534   return 0;
1535 
1536 err4:
1537   SSL_free(ssl->ssl);
1538   ssl->ssl = NULL;
1539 err3:
1540   BIO_free(ssl->rbio);
1541   BIO_free(ssl->wbio);
1542   ssl->rbio = ssl->wbio = NULL;
1543 err2:
1544   SSL_CTX_free(ssl->ctx);
1545   ssl->ctx = NULL;
1546 err1:
1547   close(hc->hc_fd);
1548   hc->hc_fd = -1;
1549   free(ssl);
1550 errnval:
1551   return -EINVAL;
1552 }
1553 
1554 http_client_t *
http_client_connect(void * aux,http_ver_t ver,const char * scheme,const char * host,int port,const char * bindaddr)1555 http_client_connect
1556   ( void *aux, http_ver_t ver, const char *scheme,
1557     const char *host, int port, const char *bindaddr )
1558 {
1559   http_client_t *hc;
1560   static int tally;
1561   int r;
1562 
1563   hc             = calloc(1, sizeof(http_client_t));
1564   pthread_mutex_init(&hc->hc_mutex, NULL);
1565   hc->hc_id      = ++tally;
1566   hc->hc_aux     = aux;
1567   hc->hc_io_size = 1024;
1568   hc->hc_rtsp_stream_id = -1;
1569   hc->hc_verify_peer = -1;
1570   hc->hc_bindaddr = bindaddr ? strdup(bindaddr) : NULL;
1571 
1572   TAILQ_INIT(&hc->hc_args);
1573   TAILQ_INIT(&hc->hc_wqueue);
1574 
1575   hc->hc_hdr_create = http_client_basic_args;
1576 
1577   pthread_mutex_lock(&hc->hc_mutex);
1578   r = http_client_reconnect(hc, ver, scheme, host, port);
1579   pthread_mutex_unlock(&hc->hc_mutex);
1580   if (r < 0) {
1581     free(hc);
1582     return NULL;
1583   }
1584 
1585   return hc;
1586 }
1587 
1588 /*
1589  * Register to the another thread
1590  */
1591 void
http_client_register(http_client_t * hc)1592 http_client_register( http_client_t *hc )
1593 {
1594   assert(hc->hc_data_received || hc->hc_conn_closed || hc->hc_data_complete);
1595   assert(hc->hc_efd == NULL);
1596 
1597   pthread_mutex_lock(&http_lock);
1598 
1599   TAILQ_INSERT_TAIL(&http_clients, hc, hc_link);
1600 
1601   hc->hc_efd  = http_poll;
1602 
1603   pthread_mutex_unlock(&http_lock);
1604 }
1605 
1606 /*
1607  * Cancel
1608  *
1609  * This function is not allowed to be called inside the callbacks for
1610  * registered clients to the http_client_thread .
1611  */
1612 void
http_client_close(http_client_t * hc)1613 http_client_close ( http_client_t *hc )
1614 {
1615   http_client_wcmd_t *wcmd;
1616   tvhpoll_event_t ev;
1617 
1618   if (hc == NULL)
1619     return;
1620 
1621   if (hc->hc_efd == http_poll) { /* http_client_thread */
1622     pthread_mutex_lock(&http_lock);
1623     hc->hc_shutdown_wait = 1;
1624     while (hc->hc_running)
1625       tvh_cond_wait(&http_cond, &http_lock);
1626     if (hc->hc_efd) {
1627       memset(&ev, 0, sizeof(ev));
1628       ev.fd = hc->hc_fd;
1629       tvhpoll_rem(hc->hc_efd, &ev, 1);
1630       TAILQ_REMOVE(&http_clients, hc, hc_link);
1631       hc->hc_efd = NULL;
1632     }
1633     pthread_mutex_unlock(&http_lock);
1634   }
1635   pthread_mutex_lock(&hc->hc_mutex);
1636   while (http_client_busy(hc)) {
1637     pthread_mutex_unlock(&hc->hc_mutex);
1638     tvh_safe_usleep(10000);
1639     pthread_mutex_lock(&hc->hc_mutex);
1640   }
1641   http_client_shutdown(hc, 1, 0);
1642   http_client_flush(hc, 0);
1643   tvhtrace(LS_HTTPC, "%04X: Closed", shortid(hc));
1644   while ((wcmd = TAILQ_FIRST(&hc->hc_wqueue)) != NULL)
1645     http_client_cmd_destroy(hc, wcmd);
1646   http_client_ssl_free(hc);
1647   rtsp_clear_session(hc);
1648   pthread_mutex_unlock(&hc->hc_mutex);
1649   pthread_mutex_destroy(&hc->hc_mutex);
1650   free(hc->hc_url);
1651   free(hc->hc_location);
1652   free(hc->hc_rbuf);
1653   free(hc->hc_data);
1654   free(hc->hc_host);
1655   free(hc->hc_scheme);
1656   free(hc->hc_bindaddr);
1657   free(hc->hc_rtsp_user);
1658   free(hc->hc_rtsp_pass);
1659 #ifdef CLANG_SANITIZER
1660   pthread_mutex_lock(&http_lock);
1661 #endif
1662   free(hc);
1663 #ifdef CLANG_SANITIZER
1664   pthread_mutex_unlock(&http_lock);
1665 #endif
1666 }
1667 
1668 /*
1669  * Initialise subsystem
1670  */
1671 pthread_t http_client_tid;
1672 
1673 void
http_client_init(const char * user_agent)1674 http_client_init ( const char *user_agent )
1675 {
1676   tvhpoll_event_t ev;
1677 
1678   http_user_agent = user_agent ? strdup(user_agent) : NULL;
1679 
1680   /* Setup list */
1681   pthread_mutex_init(&http_lock, NULL);
1682   tvh_cond_init(&http_cond);
1683   TAILQ_INIT(&http_clients);
1684 
1685   /* Setup pipe */
1686   tvh_pipe(O_NONBLOCK, &http_pipe);
1687 
1688   /* Setup poll */
1689   http_poll   = tvhpoll_create(10);
1690   memset(&ev, 0, sizeof(ev));
1691   ev.fd       = http_pipe.rd;
1692   ev.events   = TVHPOLL_IN;
1693   ev.data.ptr = &http_pipe;
1694   tvhpoll_add(http_poll, &ev, 1);
1695 
1696   /* Setup thread */
1697   atomic_set(&http_running, 1);
1698   tvhthread_create(&http_client_tid, NULL, http_client_thread, NULL, "httpc");
1699 #if HTTPCLIENT_TESTSUITE
1700   http_client_testsuite_run();
1701 #endif
1702 }
1703 
1704 void
http_client_done(void)1705 http_client_done ( void )
1706 {
1707   http_client_t *hc;
1708 
1709   atomic_set(&http_running, 0);
1710   tvh_write(http_pipe.wr, "", 1);
1711   pthread_join(http_client_tid, NULL);
1712   tvh_pipe_close(&http_pipe);
1713   pthread_mutex_lock(&http_lock);
1714   TAILQ_FOREACH(hc, &http_clients, hc_link)
1715     if (hc->hc_efd == http_poll)
1716       hc->hc_efd = NULL;
1717   tvhpoll_destroy(http_poll);
1718   http_poll = NULL;
1719   pthread_mutex_unlock(&http_lock);
1720   free(http_user_agent);
1721 }
1722 
1723 /*
1724  *
1725  * TESTSUITE
1726  *
1727  */
1728 
1729 #if HTTPCLIENT_TESTSUITE
1730 
1731 static int
http_client_testsuite_hdr_received(http_client_t * hc)1732 http_client_testsuite_hdr_received( http_client_t *hc )
1733 {
1734   http_arg_t *ra;
1735 
1736   fprintf(stderr, "HTTPCTS: Received header from %s:%i\n", hc->hc_host, hc->hc_port);
1737   TAILQ_FOREACH(ra, &hc->hc_args, link)
1738     fprintf(stderr, "  %s: %s\n", ra->key, ra->val);
1739   return 0;
1740 }
1741 
1742 static void
http_client_testsuite_conn_closed(http_client_t * hc,int result)1743 http_client_testsuite_conn_closed( http_client_t *hc, int result )
1744 {
1745   fprintf(stderr, "HTTPCTS: Closed (result=%i - %s)\n", result, strerror(result));
1746 }
1747 
1748 static int
http_client_testsuite_data_complete(http_client_t * hc)1749 http_client_testsuite_data_complete( http_client_t *hc )
1750 {
1751   fprintf(stderr, "HTTPCTS: Data Complete (code=%i, data=%p, data_size=%zi)\n",
1752           hc->hc_code, hc->hc_data, hc->hc_data_size);
1753   return 0;
1754 }
1755 
1756 static int
http_client_testsuite_data_received(http_client_t * hc,void * data,size_t len)1757 http_client_testsuite_data_received( http_client_t *hc, void *data, size_t len )
1758 {
1759   fprintf(stderr, "HTTPCTS: Data received (len=%zi)\n", len);
1760   /* check, if the data memory area is OK */
1761   memset(data, 0xa5, len);
1762   return 0;
1763 }
1764 
1765 static struct strtab HTTP_contab[] = {
1766   { "WAIT_REQUEST", HTTP_CON_WAIT_REQUEST },
1767   { "READ_HEADER",  HTTP_CON_READ_HEADER },
1768   { "END",          HTTP_CON_END },
1769   { "POST_DATA",    HTTP_CON_POST_DATA },
1770   { "SENDING",      HTTP_CON_SENDING },
1771   { "SENT",         HTTP_CON_SENT },
1772   { "RECEIVING",    HTTP_CON_RECEIVING },
1773   { "DONE",         HTTP_CON_DONE },
1774 };
1775 
1776 static struct strtab ERRNO_tab[] = {
1777   { "EPERM",           EPERM },
1778   { "ENOENT",          ENOENT },
1779   { "ESRCH",           ESRCH },
1780   { "EINTR",           EINTR },
1781   { "EIO",             EIO },
1782   { "ENXIO",           ENXIO },
1783   { "E2BIG",           E2BIG },
1784   { "ENOEXEC",         ENOEXEC },
1785   { "EBADF",           EBADF },
1786   { "ECHILD",          ECHILD },
1787   { "EAGAIN",          EAGAIN },
1788   { "ENOMEM",          ENOMEM },
1789   { "EACCES",          EACCES },
1790   { "EFAULT",          EFAULT },
1791   { "ENOTBLK",         ENOTBLK },
1792   { "EBUSY",           EBUSY },
1793   { "EEXIST",          EEXIST },
1794   { "EXDEV",           EXDEV },
1795   { "ENODEV",          ENODEV },
1796   { "ENOTDIR",         ENOTDIR },
1797   { "EISDIR",          EISDIR },
1798   { "EINVAL",          EINVAL },
1799   { "ENFILE",          ENFILE },
1800   { "EMFILE",          EMFILE },
1801   { "ENOTTY",          ENOTTY },
1802   { "ETXTBSY",         ETXTBSY },
1803   { "EFBIG",           EFBIG },
1804   { "ENOSPC",          ENOSPC },
1805   { "ESPIPE",          ESPIPE },
1806   { "EROFS",           EROFS },
1807   { "EMLINK",          EMLINK },
1808   { "EPIPE",           EPIPE },
1809   { "EDOM",            EDOM },
1810   { "ERANGE",          ERANGE },
1811 #ifdef __linux__
1812   { "EDEADLK",         EDEADLK },
1813   { "ENAMETOOLONG",    ENAMETOOLONG },
1814   { "ENOLCK",          ENOLCK },
1815   { "ENOSYS",          ENOSYS },
1816   { "ENOTEMPTY",       ENOTEMPTY },
1817   { "ELOOP",           ELOOP },
1818   { "EWOULDBLOCK",     EWOULDBLOCK },
1819   { "ENOMSG",          ENOMSG },
1820   { "EIDRM",           EIDRM },
1821   { "ECHRNG",          ECHRNG },
1822   { "EL2NSYNC",        EL2NSYNC },
1823   { "EL3HLT",          EL3HLT },
1824   { "EL3RST",          EL3RST },
1825   { "ELNRNG",          ELNRNG },
1826   { "EUNATCH",         EUNATCH },
1827   { "ENOCSI",          ENOCSI },
1828   { "EL2HLT",          EL2HLT },
1829   { "EBADE",           EBADE },
1830   { "EBADR",           EBADR },
1831   { "EXFULL",          EXFULL },
1832   { "ENOANO",          ENOANO },
1833   { "EBADRQC",         EBADRQC },
1834   { "EBADSLT",         EBADSLT },
1835   { "EDEADLOCK",       EDEADLOCK },
1836   { "EBFONT",          EBFONT },
1837   { "ENOSTR",          ENOSTR },
1838   { "ENODATA",         ENODATA },
1839   { "ETIME",           ETIME },
1840   { "ENOSR",           ENOSR },
1841   { "ENONET",          ENONET },
1842   { "ENOPKG",          ENOPKG },
1843   { "EREMOTE",         EREMOTE },
1844   { "ENOLINK",         ENOLINK },
1845   { "EADV",            EADV },
1846   { "ESRMNT",          ESRMNT },
1847   { "ECOMM",           ECOMM },
1848   { "EPROTO",          EPROTO },
1849   { "EMULTIHOP",       EMULTIHOP },
1850   { "EDOTDOT",         EDOTDOT },
1851   { "EBADMSG",         EBADMSG },
1852   { "EOVERFLOW",       EOVERFLOW },
1853   { "ENOTUNIQ",        ENOTUNIQ },
1854   { "EBADFD",          EBADFD },
1855   { "EREMCHG",         EREMCHG },
1856   { "ELIBACC",         ELIBACC },
1857   { "ELIBBAD",         ELIBBAD },
1858   { "ELIBSCN",         ELIBSCN },
1859   { "ELIBMAX",         ELIBMAX },
1860   { "ELIBEXEC",        ELIBEXEC },
1861   { "EILSEQ",          EILSEQ },
1862   { "ERESTART",        ERESTART },
1863   { "ESTRPIPE",        ESTRPIPE },
1864   { "EUSERS",          EUSERS },
1865   { "ENOTSOCK",        ENOTSOCK },
1866   { "EDESTADDRREQ",    EDESTADDRREQ },
1867   { "EMSGSIZE",        EMSGSIZE },
1868   { "EPROTOTYPE",      EPROTOTYPE },
1869   { "ENOPROTOOPT",     ENOPROTOOPT },
1870   { "EPROTONOSUPPORT", EPROTONOSUPPORT },
1871   { "ESOCKTNOSUPPORT", ESOCKTNOSUPPORT },
1872   { "EOPNOTSUPP",      EOPNOTSUPP },
1873   { "EPFNOSUPPORT",    EPFNOSUPPORT },
1874   { "EAFNOSUPPORT",    EAFNOSUPPORT },
1875   { "EADDRINUSE",      EADDRINUSE },
1876   { "EADDRNOTAVAIL",   EADDRNOTAVAIL },
1877   { "ENETDOWN",        ENETDOWN },
1878   { "ENETUNREACH",     ENETUNREACH },
1879   { "ENETRESET",       ENETRESET },
1880   { "ECONNABORTED",    ECONNABORTED },
1881   { "ECONNRESET",      ECONNRESET },
1882   { "ENOBUFS",         ENOBUFS },
1883   { "EISCONN",         EISCONN },
1884   { "ENOTCONN",        ENOTCONN },
1885   { "ESHUTDOWN",       ESHUTDOWN },
1886   { "ETOOMANYREFS",    ETOOMANYREFS },
1887   { "ETIMEDOUT",       ETIMEDOUT },
1888   { "ECONNREFUSED",    ECONNREFUSED },
1889   { "EHOSTDOWN",       EHOSTDOWN },
1890   { "EHOSTUNREACH",    EHOSTUNREACH },
1891   { "EALREADY",        EALREADY },
1892   { "EINPROGRESS",     EINPROGRESS },
1893   { "ESTALE",          ESTALE },
1894   { "EUCLEAN",         EUCLEAN },
1895   { "ENOTNAM",         ENOTNAM },
1896   { "ENAVAIL",         ENAVAIL },
1897   { "EISNAM",          EISNAM },
1898   { "EREMOTEIO",       EREMOTEIO },
1899   { "EDQUOT",          EDQUOT },
1900   { "ENOMEDIUM",       ENOMEDIUM },
1901   { "EMEDIUMTYPE",     EMEDIUMTYPE },
1902   { "ECANCELED",       ECANCELED },
1903   { "ENOKEY",          ENOKEY },
1904   { "EKEYEXPIRED",     EKEYEXPIRED },
1905   { "EKEYREVOKED",     EKEYREVOKED },
1906   { "EKEYREJECTED",    EKEYREJECTED },
1907   { "EOWNERDEAD",      EOWNERDEAD },
1908   { "ENOTRECOVERABLE", ENOTRECOVERABLE },
1909 #ifdef ERFKILL
1910   { "ERFKILL",         ERFKILL },
1911 #endif
1912 #ifdef EHWPOISON
1913   { "EHWPOISON",       EHWPOISON },
1914 #endif
1915 #endif /* __linux__ */
1916 };
1917 
1918 void
http_client_testsuite_run(void)1919 http_client_testsuite_run( void )
1920 {
1921   const char *path, *cs, *cs2;
1922   char line[1024], *s;
1923   http_arg_list_t args;
1924   http_client_t *hc = NULL;
1925   http_cmd_t cmd;
1926   http_ver_t ver = HTTP_VERSION_1_1;
1927   int data_transfer = 0, port = 0;
1928   size_t data_limit = 0;
1929   tvhpoll_event_t ev;
1930   tvhpoll_t *efd;
1931   url_t u1, u2;
1932   FILE *fp;
1933   int r, expected = HTTP_CON_DONE, expected_code = 200;
1934   int handle_location = 0;
1935   int peer_verify = 1;
1936   int repeat = 0, repeat2;
1937 
1938   path = getenv("TVHEADEND_HTTPC_TEST");
1939   if (path == NULL)
1940     path = TVHEADEND_DATADIR "/support/httpc-test.txt";
1941   fp = tvh_fopen(path, "r");
1942   if (fp == NULL) {
1943     tvhnotice(LS_HTTPC, "Test: unable to open '%s': %s", path, strerror(errno));
1944     return;
1945   }
1946   urlinit(&u1);
1947   urlinit(&u2);
1948   http_arg_init(&args);
1949   efd = tvhpoll_create(1);
1950   while (fgets(line, sizeof(line), fp) != NULL && tvheadend_is_running()) {
1951     if (line[0] == '\0')
1952       continue;
1953     s = line + strlen(line) - 1;
1954     while (*s < ' ' && s != line)
1955       s--;
1956     if (*s < ' ')
1957       *s = '\0';
1958     else
1959       s[1] = '\0';
1960     s = line;
1961     while (*s && *s < ' ')
1962       s++;
1963     if (*s == '\0' || *s == '#')
1964       continue;
1965     if (strcmp(s, "Reset=1") == 0) {
1966       ver = HTTP_VERSION_1_1;
1967       urlreset(&u1);
1968       urlreset(&u2);
1969       http_client_close(hc);
1970       hc = NULL;
1971       data_transfer = 0;
1972       data_limit = 0;
1973       port = 0;
1974       expected = HTTP_CON_DONE;
1975       expected_code = 200;
1976       handle_location = 0;
1977       peer_verify = 1;
1978       repeat = 0;
1979     } else if (strcmp(s, "DataTransfer=all") == 0) {
1980       data_transfer = 0;
1981     } else if (strcmp(s, "DataTransfer=cont") == 0) {
1982       data_transfer = 1;
1983     } else if (strcmp(s, "HandleLocation=0") == 0) {
1984       handle_location = 0;
1985     } else if (strcmp(s, "HandleLocation=1") == 0) {
1986       handle_location = 1;
1987     } else if (strcmp(s, "SSLPeerVerify=0") == 0) {
1988       peer_verify = 0;
1989     } else if (strcmp(s, "SSLPeerVerify=1") == 0) {
1990       peer_verify = 1;
1991     } else if (strncmp(s, "DataLimit=", 10) == 0) {
1992       data_limit = atoll(s + 10);
1993     } else if (strncmp(s, "Port=", 5) == 0) {
1994       port = atoi(s + 5);
1995     } else if (strncmp(s, "ExpectedError=", 14) == 0) {
1996       r = str2val(s + 14, HTTP_contab);
1997       if (r < 0) {
1998         r = str2val(s + 14, ERRNO_tab);
1999         if (r < 0) {
2000           fprintf(stderr, "HTTPCTS: Unknown error code '%s'\n", s + 14);
2001           goto fatal;
2002         } else {
2003           r = -r;
2004         }
2005       }
2006       expected = r;
2007     } else if (strncmp(s, "ExpectedCode=", 13) == 0) {
2008       expected_code = atoi(s + 13);
2009     } else if (strncmp(s, "Header=", 7) == 0) {
2010       r = http_client_parse_arg(&args, s + 7);
2011       if (r < 0)
2012         goto fatal;
2013     } else if (strncmp(s, "Version=", 8) == 0) {
2014       ver = http_str2ver(s + 8);
2015     } else if (strncmp(s, "URL=", 4) == 0) {
2016       urlreset(&u1);
2017       if (urlparse(s + 4, &u1) < 0) {
2018         fprintf(stderr, "HTTPCTS: Parse URL error for '%s'\n", s + 4);
2019         goto fatal;
2020       }
2021     } else if (strncmp(s, "Repeat=", 7) == 0) {
2022       repeat = atoi(s + 7);
2023     } else if (strncmp(s, "Command=", 8) == 0) {
2024       if (strcmp(s + 8, "EXIT") == 0)
2025         break;
2026       if (tvh_str_default(u1.host, NULL) == NULL) {
2027         fprintf(stderr, "HTTPCTS: Define URL\n");
2028         goto fatal;
2029       }
2030       cmd = http_str2cmd(s + 8);
2031       repeat2 = 0;
2032 rep:
2033       http_client_basic_args(hc, &args, &u1, 1);
2034       if (u2.host == NULL || u1.host == NULL || strcmp(u1.host, u2.host) ||
2035           u2.port != u1.port || (hc && !hc->hc_keepalive)) {
2036         http_client_close(hc);
2037         if (port)
2038           u1.port = port;
2039         hc = http_client_connect(NULL, ver, u1.scheme, u1.host, u1.port, NULL);
2040         if (hc == NULL) {
2041           fprintf(stderr, "HTTPCTS: Unable to connect to %s:%i (%s)\n", u1.host, u1.port, u1.scheme);
2042           goto fatal;
2043         } else {
2044           fprintf(stderr, "HTTPCTS: Connected to %s:%i\n", hc->hc_host, hc->hc_port);
2045         }
2046         http_client_ssl_peer_verify(hc, peer_verify);
2047         urlreset(&u2);
2048         urlcopy(&u2, &u1);
2049       }
2050       fprintf(stderr, "HTTPCTS Send: Cmd=%s Ver=%s Host=%s Path=%s\n",
2051               http_cmd2str(cmd), http_ver2str(ver), http_arg_get(&args, "Host"), u1.path);
2052       hc->hc_efd = efd;
2053       hc->hc_handle_location = handle_location;
2054       hc->hc_data_limit = data_limit;
2055       hc->hc_hdr_received = http_client_testsuite_hdr_received;
2056       hc->hc_data_complete = http_client_testsuite_data_complete;
2057       hc->hc_conn_closed = http_client_testsuite_conn_closed;
2058       if (data_transfer) {
2059         hc->hc_data_received = http_client_testsuite_data_received;
2060       } else {
2061         hc->hc_data_received = NULL;
2062       }
2063       r = http_client_send(hc, cmd, u1.path, u1.query, &args, NULL, 0);
2064       if (r < 0) {
2065         fprintf(stderr, "HTTPCTS Send Failed %s\n", strerror(-r));
2066         goto fatal;
2067       }
2068       while (tvheadend_is_running()) {
2069         fprintf(stderr, "HTTPCTS: Enter Poll\n");
2070         r = tvhpoll_wait(efd, &ev, 1, -1);
2071         fprintf(stderr, "HTTPCTS: Leave Poll: %i (%s)\n", r, r < 0 ? val2str(-r, ERRNO_tab) : "OK");
2072         if (r < 0 && ERRNO_AGAIN(errno))
2073           continue;
2074         if (r < 0) {
2075           fprintf(stderr, "HTTPCTS: Poll result: %s\n", strerror(-r));
2076           goto fatal;
2077         }
2078         if (r != 1)
2079           continue;
2080         if (ev.data.ptr != hc) {
2081           fprintf(stderr, "HTTPCTS: Poll returned a wrong value\n");
2082           goto fatal;
2083         }
2084         r = http_client_run(hc);
2085         cs = val2str(r, HTTP_contab);
2086         if (cs == NULL)
2087           cs = val2str(-r, ERRNO_tab);
2088         cs2 = val2str(expected, HTTP_contab);
2089         if (cs2 == NULL)
2090           cs2 = val2str(-expected, ERRNO_tab);
2091         fprintf(stderr, "HTTPCTS: Run Done, Result = %i (%s), Expected = %i (%s)\n", r, cs, expected, cs2);
2092         if (r == expected) {
2093           if (hc->hc_code != expected_code) {
2094             fprintf(stderr, "HTTPCTS: HTTP Code Fail: Expected = %i Got = %i\n", expected_code, hc->hc_code);
2095             goto fatal;
2096           }
2097           break;
2098         }
2099         if (r < 0)
2100           goto fatal;
2101         if (r == HTTP_CON_DONE)
2102           goto fatal;
2103       }
2104       if (repeat2++ < repeat)
2105         goto rep;
2106       urlreset(&u1);
2107       http_client_clear_state(hc);
2108     } else {
2109       fprintf(stderr, "HTTPCTS: Wrong line '%s'\n", s);
2110     }
2111   }
2112   urlreset(&u2);
2113   urlreset(&u1);
2114   http_client_close(hc);
2115   tvhpoll_destroy(efd);
2116   http_arg_flush(&args);
2117   fclose(fp);
2118   fprintf(stderr, "HTTPCTS Return To Main\n");
2119   return;
2120 fatal:
2121   fprintf(stderr, "HTTPCTS Fatal Error\n");
2122   exit(1);
2123 }
2124 
2125 #endif
2126