#include <openssl/err.h>
#include <openssl/ssl.h>
+#if ENABLE_TRACE
#define HTTPCLIENT_TESTSUITE 1
+#endif
struct http_client_ssl {
int connected;
ssize_t r, r2;
int e;
+ if (hc->hc_verify_peer < 0)
+ http_client_ssl_peer_verify(hc, 1); /* default method - verify */
while (1) {
if (!ssl->connected) {
r = SSL_connect(ssl->ssl);
if (r > 0) {
ssl->connected = 1;
+ if (hc->hc_verify_peer > 0) {
+ if (SSL_get_peer_certificate(ssl->ssl) == NULL ||
+ SSL_get_verify_result(ssl->ssl) != X509_V_OK) {
+ tvhlog(LOG_ERR, "httpc", "SSL peer verification failed (%s:%i)%s %li",
+ hc->hc_host, hc->hc_port,
+ SSL_get_peer_certificate(ssl->ssl) ? " X509" : "",
+ SSL_get_verify_result(ssl->ssl));
+ errno = EPERM;
+ return -1;
+ }
+ }
goto write;
}
} else {
urlreset(&u);
return r;
}
+ r = hc->hc_verify_peer;
+ hc->hc_verify_peer = -1;
+ http_client_ssl_peer_verify(hc, r);
hc->hc_efd = efd;
}
&h, NULL, 0);
}
+void
+http_client_ssl_peer_verify( http_client_t *hc, int verify )
+{
+ struct http_client_ssl *ssl;
+
+ if (hc->hc_verify_peer < 0) {
+ hc->hc_verify_peer = verify ? 1 : 0;
+ if ((ssl = hc->hc_ssl) != NULL) {
+ if (!SSL_CTX_set_default_verify_paths(ssl->ctx))
+ tvherror("httpc", "SSL - unable to load CA certificates for verification");
+ SSL_CTX_set_verify_depth(ssl->ctx, 1);
+ SSL_CTX_set_verify(ssl->ctx,
+ hc->hc_verify_peer ? SSL_VERIFY_PEER : SSL_VERIFY_NONE,
+ NULL);
+ }
+ } else {
+ tvherror("httpc", "SSL peer verification method must be set only once");
+ }
+}
+
/*
* Data thread
*/
tvhlog(LOG_ERR, "httpc", "Unable to connect to %s:%i - %s", host, port, errbuf);
return -EINVAL;
}
+ tvhtrace("httpc", "Connected to %s:%i", host, port);
http_client_ssl_free(hc);
if (strcasecmp(scheme, "https") == 0 || strcasecmp(scheme, "rtsps") == 0) {
ssl = calloc(1, sizeof(*ssl));
hc->hc_aux = aux;
hc->hc_io_size = 1024;
hc->hc_rtsp_stream_id = -1;
+ hc->hc_verify_peer = -1;
TAILQ_INIT(&hc->hc_args);
TAILQ_INIT(&hc->hc_wqueue);
FILE *fp;
int r, expected = HTTP_CON_DONE;
int handle_location = 0;
+ int peer_verify = 1;
path = getenv("TVHEADEND_HTTPC_TEST");
if (path == NULL)
path = TVHEADEND_DATADIR "/support/httpc-test.txt";
fp = fopen(path, "r");
if (fp == NULL) {
- tvhlog(LOG_ERR, "httpc", "Test: unable to open '%s': %s", path, strerror(errno));
+ tvhlog(LOG_NOTICE, "httpc", "Test: unable to open '%s': %s", path, strerror(errno));
return;
}
memset(&u1, 0, sizeof(u1));
port = 0;
expected = HTTP_CON_DONE;
handle_location = 0;
+ peer_verify = 1;
} else if (strcmp(s, "DataTransfer=all") == 0) {
data_transfer = 0;
} else if (strcmp(s, "DataTransfer=cont") == 0) {
handle_location = 0;
} else if (strcmp(s, "HandleLocation=1") == 0) {
handle_location = 1;
+ } else if (strcmp(s, "SSLPeerVerify=0") == 0) {
+ peer_verify = 0;
+ } else if (strcmp(s, "SSLPeerVerify=1") == 0) {
+ peer_verify = 1;
} else if (strncmp(s, "DataLimit=", 10) == 0) {
data_limit = atoll(s + 10);
} else if (strncmp(s, "Port=", 5) == 0) {
if (urlparse(s + 4, &u1) < 0)
goto fatal;
} else if (strncmp(s, "Command=", 8) == 0) {
+ if (strcmp(s + 8, "EXIT") == 0)
+ break;
if (u1.host == NULL || u1.host[0] == '\0') {
fprintf(stderr, "HTTPCTS: Define URL\n");
goto fatal;
} else {
fprintf(stderr, "HTTPCTS: Connected to %s:%i\n", hc->hc_host, hc->hc_port);
}
+ http_client_ssl_peer_verify(hc, peer_verify);
}
fprintf(stderr, "HTTPCTS Send: Cmd=%s Ver=%s Host=%s Path=%s\n",
http_cmd2str(cmd), http_ver2str(ver), http_arg_get(&args, "Host"), u1.path);
#include "redblack.h"
#include "notify.h"
#include "prop.h"
-
-#if ENABLE_IMAGECACHE
-#define CURL_STATICLIB
-#include <curl/curl.h>
-#include <curl/easy.h>
-#endif
+#include "http.h"
/*
* Image metadata
static int
imagecache_image_fetch ( imagecache_image_t *img )
{
- int res = 1;
- CURL *curl;
+ int res = 1, r;
FILE *fp;
+ url_t url;
char tmp[256], path[256];
+ tvhpoll_event_t ev;
+ tvhpoll_t *efd = NULL;
+ http_client_t *hc;
+
+ memset(&url, 0, sizeof(url));
/* Open file */
if (hts_settings_buildpath(path, sizeof(path), "imagecache/data/%d",
/* Build command */
tvhlog(LOG_DEBUG, "imagecache", "fetch %s", img->url);
- curl = curl_easy_init();
- curl_easy_setopt(curl, CURLOPT_URL, img->url);
- curl_easy_setopt(curl, CURLOPT_WRITEDATA, fp);
- curl_easy_setopt(curl, CURLOPT_USERAGENT, "TVHeadend");
- curl_easy_setopt(curl, CURLOPT_TIMEOUT, 120);
- curl_easy_setopt(curl, CURLOPT_NOPROGRESS, 1);
- curl_easy_setopt(curl, CURLOPT_FAILONERROR, 1);
- if (imagecache_conf.ignore_sslcert)
- curl_easy_setopt(curl, CURLOPT_SSL_VERIFYPEER, 0);
+ memset(&url, 0, sizeof(url));
+ if (urlparse(img->url, &url)) {
+ tvherror("imagecache", "Unable to parse url '%s'", img->url);
+ goto error;
+ }
/* Fetch (release lock, incase of delays) */
pthread_mutex_unlock(&global_lock);
- res = curl_easy_perform(curl);
- curl_easy_cleanup(curl);
- fclose(fp);
+
+ hc = http_client_connect(NULL, HTTP_VERSION_1_1, url.scheme,
+ url.host, url.port);
+ if (hc == NULL)
+ goto error;
+
+ http_client_ssl_peer_verify(hc, imagecache_conf.ignore_sslcert ? 0 : 1);
+ hc->hc_handle_location = 1;
+ hc->hc_data_limit = 256*1024;
+ efd = tvhpoll_create(1);
+ hc->hc_efd = efd;
+
+ r = http_client_simple(hc, &url);
+ if (r < 0)
+ goto error;
+
+ while (tvheadend_running) {
+ r = tvhpoll_wait(efd, &ev, 1, -1);
+ if (r < 0)
+ break;
+ if (r == 0)
+ continue;
+ r = http_client_run(hc);
+ if (r < 0)
+ break;
+ if (r == HTTP_CON_DONE) {
+ if (hc->hc_code == HTTP_STATUS_OK && hc->hc_data_size > 0) {
+ fwrite(hc->hc_data, hc->hc_data_size, 1, fp);
+ res = 0;
+ }
+ break;
+ }
+ }
+
pthread_mutex_lock(&global_lock);
/* Process */
error:
+ urlreset(&url);
+ tvhpoll_destroy(efd);
img->state = IDLE;
time(&img->updated); // even if failed (possibly request sooner?)
if (res) {