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