42#include <libwapcaplet/libwapcaplet.h>
43#include <nsutils/time.h>
67#define UPDATES_PER_SECOND 2
72#define CIPHER_SUITES \
73 "TLS_AES_256_GCM_SHA384:" \
74 "TLS_CHACHA20_POLY1305_SHA256:" \
75 "TLS_AES_128_GCM_SHA256"
84 "EECDH+AESGCM+TLSv1.2:" \
95#define CIPHER_LIST_LEGACY \
106#include <openssl/ssl.h>
107#include <openssl/x509v3.h>
132 port = lwc_string_ref(corestring_lwc_443);
134 hash = lwc_string_hash_value(hostname) ^ lwc_string_hash_value(port);
136 lwc_string_unref(hostname);
137 lwc_string_unref(port);
155 port1 = lwc_string_ref(corestring_lwc_443);
157 port2 = lwc_string_ref(corestring_lwc_443);
159 if (lwc_string_isequal(hostname1, hostname2, &iseq) != lwc_error_ok ||
164 if (lwc_string_isequal(port1, port2, &iseq) != lwc_error_ok)
168 lwc_string_unref(hostname1);
169 lwc_string_unref(hostname2);
170 lwc_string_unref(port1);
171 lwc_string_unref(port2);
193 NSLOG(netsurf, WARNING,
"Problem freeing SSL certificate chain");
214#if LIBCURL_VERSION_NUM >= 0x072000
215#define NSCURLOPT_PROGRESS_FUNCTION CURLOPT_XFERINFOFUNCTION
216#define NSCURLOPT_PROGRESS_DATA CURLOPT_XFERINFODATA
217#define NSCURL_PROGRESS_T curl_off_t
219#define NSCURLOPT_PROGRESS_FUNCTION CURLOPT_PROGRESSFUNCTION
220#define NSCURLOPT_PROGRESS_DATA CURLOPT_PROGRESSDATA
221#define NSCURL_PROGRESS_T double
224#if LIBCURL_VERSION_NUM >= 0x073800
225#define NSCURL_POSTDATA_T curl_mime
226#define NSCURL_POSTDATA_CURLOPT CURLOPT_MIMEPOST
227#define NSCURL_POSTDATA_FREE(x) curl_mime_free(x)
229#define NSCURL_POSTDATA_T struct curl_httppost
230#define NSCURL_POSTDATA_CURLOPT CURLOPT_HTTPPOST
231#define NSCURL_POSTDATA_FREE(x) curl_formfree(x)
300 NSLOG(netsurf, INFO,
"Initialise cURL fetcher for %s",
301 lwc_string_data(scheme));
317 NSLOG(netsurf, INFO,
"Finalise cURL fetcher %s",
318 lwc_string_data(scheme));
323 "All cURL fetchers finalised, closing down cURL");
328 if (codem != CURLM_OK)
330 "curl_multi_cleanup failed: ignoring");
332 curl_global_cleanup();
334 NSLOG(netsurf, DEBUG,
"Cleaning up SSL cert chain hashmap");
343 lwc_string_unref(h->
host);
344 curl_easy_cleanup(h->
handle);
372 if (postdata != NULL) {
381 }
else if (post_multipart) {
400 if (postdata != NULL) {
401 switch (postdata->
type) {
426 fetch->curl_handle = NULL;
427 fetch->sent_ssl_chain =
false;
428 fetch->had_headers =
false;
429 fetch->abort =
false;
430 fetch->stopped =
false;
431 fetch->only_2xx =
false;
432 fetch->downgrade_tls =
false;
433 fetch->headers = NULL;
436 fetch->location = NULL;
437 fetch->content_length = 0;
439 fetch->cookie_string = NULL;
441 fetch->last_progress_update = 0;
442 fetch->postdata = NULL;
443 fetch->curl_postdata = NULL;
446 memset(
fetch->cert_data, 0,
sizeof(
fetch->cert_data));
447 fetch->cert_depth = -1;
478 const char *post_urlenc,
483 struct curl_slist *slist;
492 fetch->only_2xx = only_2xx;
493 fetch->downgrade_tls = downgrade_tls;
494 fetch->fetch_handle = parent_fetch;
501 if (
fetch->postdata == NULL) {
505#define APPEND(list, value) \
506 slist = curl_slist_append(list, value); \
521 snprintf(s,
sizeof s,
"Accept-Language: %s, *;q=0.1",
530 snprintf(s,
sizeof s,
"Accept-Charset: %s, *;q=0.1",
541 for (i = 0; headers[i] != NULL; i++) {
555 curl_slist_free_all(
fetch->headers);
591 memset(&chain, 0,
sizeof(chain));
596 for (depth = 0; depth < chain.
depth; depth++) {
597 if (certs[depth].
cert == NULL) {
604 switch (certs[depth].
err) {
609 case X509_V_ERR_UNABLE_TO_GET_ISSUER_CERT:
611 case X509_V_ERR_UNABLE_TO_DECODE_ISSUER_PUBLIC_KEY:
615 case X509_V_ERR_UNABLE_TO_DECRYPT_CERT_SIGNATURE:
617 case X509_V_ERR_UNABLE_TO_DECRYPT_CRL_SIGNATURE:
619 case X509_V_ERR_CERT_SIGNATURE_FAILURE:
621 case X509_V_ERR_CRL_SIGNATURE_FAILURE:
625 case X509_V_ERR_CERT_NOT_YET_VALID:
627 case X509_V_ERR_CRL_NOT_YET_VALID:
631 case X509_V_ERR_CERT_HAS_EXPIRED:
633 case X509_V_ERR_CRL_HAS_EXPIRED:
637 case X509_V_ERR_DEPTH_ZERO_SELF_SIGNED_CERT:
641 case X509_V_ERR_SELF_SIGNED_CERT_IN_CHAIN:
645 case X509_V_ERR_CERT_REVOKED:
649 case X509_V_ERR_HOSTNAME_MISMATCH:
661 mem = BIO_new(BIO_s_mem());
662 i2d_X509_bio(mem, certs[depth].
cert);
663 BIO_get_mem_ptr(mem, &buf[depth]);
664 (void) BIO_set_close(mem, BIO_NOCLOSE);
667 chain.
certs[depth].
der = (uint8_t *)buf[depth]->data;
672 cached_chain = fetch_curl_get_cached_chain(f);
679 for (depth = 0; depth < chain.
depth; depth++) {
683 if (buf[depth] != NULL) {
684 BUF_MEM_free(buf[depth]);
709fetch_curl_verify_callback(
int verify_ok, X509_STORE_CTX *x509_ctx)
714 depth = X509_STORE_CTX_get_error_depth(x509_ctx);
715 fetch = X509_STORE_CTX_get_app_data(x509_ctx);
719 X509_STORE_CTX_set_error(x509_ctx,
720 X509_V_ERR_CERT_CHAIN_TOO_LONG);
725 if (depth >
fetch->cert_depth) {
726 fetch->cert_depth = depth;
732 if (!
fetch->cert_data[depth].cert) {
733 fetch->cert_data[depth].cert = X509_STORE_CTX_get_current_cert(x509_ctx);
734 X509_up_ref(
fetch->cert_data[depth].cert);
735 fetch->cert_data[depth].err = X509_STORE_CTX_get_error(x509_ctx);
743 for (depth =
fetch->cert_depth; depth > 0; depth--) {
744 if (
fetch->cert_data[depth].err != 0) {
747 X509_STORE_CTX_set_error(x509_ctx,
fetch->cert_data[depth].err);
766static int fetch_curl_cert_verify_callback(X509_STORE_CTX *x509_ctx,
void *parm)
770 X509_VERIFY_PARAM *vparam;
773 vparam = X509_STORE_CTX_get0_param(x509_ctx);
774 X509_VERIFY_PARAM_set_hostflags(vparam, X509_CHECK_FLAG_NO_PARTIAL_WILDCARDS);
776 ok = X509_VERIFY_PARAM_set1_host(vparam,
777 lwc_string_data(f->
host),
778 lwc_string_length(f->
host));
782 ok = X509_STORE_CTX_set_app_data(x509_ctx, parm);
787 ok = X509_verify_cert(x509_ctx);
790 fetch_curl_store_certs_in_cache(f);
805fetch_curl_sslctxfun(CURL *
curl_handle,
void *_sslctx,
void *parm)
808 SSL_CTX *sslctx = _sslctx;
809 long options = SSL_OP_ALL | SSL_OP_NO_SSLv2 | SSL_OP_NO_SSLv3 |
810 SSL_OP_NO_TLSv1 | SSL_OP_NO_TLSv1_1;
813 SSL_CTX_set_verify(sslctx, SSL_VERIFY_PEER, fetch_curl_verify_callback);
816 SSL_CTX_set_cert_verify_callback(sslctx,
817 fetch_curl_cert_verify_callback,
822#ifdef SSL_OP_NO_TLSv1_3
825#ifdef SSL_MODE_SEND_FALLBACK_SCSV
827 SSL_CTX_set_mode(sslctx, SSL_MODE_SEND_FALLBACK_SCSV);
831 SSL_CTX_set_options(sslctx,
options);
833#ifdef SSL_OP_NO_TICKET
834 SSL_CTX_clear_options(sslctx, SSL_OP_NO_TICKET);
865#if LIBCURL_VERSION_NUM >= 0x073800
870struct curl_mime_ctx {
876static size_t mime_data_read_callback(
char *
buffer,
size_t size,
size_t nitems,
void *arg)
878 struct curl_mime_ctx *mctx = (
struct curl_mime_ctx *) arg;
879 curl_off_t sz = mctx->size - mctx->position;
882 if(sz > (curl_off_t)nitems) {
886 memcpy(
buffer, mctx->buffer + mctx->position, sz);
888 mctx->position += sz;
892static int mime_data_seek_callback(
void *arg, curl_off_t offset,
int origin)
894 struct curl_mime_ctx *mctx = (
struct curl_mime_ctx *) arg;
898 offset += mctx->size;
901 offset += mctx->position;
906 return CURL_SEEKFUNC_FAIL;
908 mctx->position = offset;
909 return CURL_SEEKFUNC_OK;
912static void mime_data_free_callback(
void *arg)
914 struct curl_mime_ctx *mctx = (
struct curl_mime_ctx *) arg;
930 CURLcode code = CURLE_OK;
933 cmime = curl_mime_init(chandle);
935 NSLOG(netsurf, WARNING,
"postdata conversion failed to curl mime context");
940 for (; multipart != NULL; multipart = multipart->
next) {
941 part = curl_mime_addpart(cmime);
946 code = curl_mime_name(part, multipart->
name);
947 if (code != CURLE_OK) {
951 value_len = strlen(multipart->
value);
953 if (multipart->
file && value_len==0) {
955 code=curl_mime_data(part, multipart->
value, value_len);
956 if (code != CURLE_OK) {
960 code = curl_mime_filename(part,
"");
961 if (code != CURLE_OK) {
965 code = curl_mime_type(part,
"application/octet-stream");
966 if (code != CURLE_OK) {
970 }
else if(multipart->
file) {
973 char *leafname = NULL;
974 char *mimetype = NULL;
976 code = curl_mime_filedata(part, multipart->
rawfile);
977 if (code != CURLE_OK) {
985 code = curl_mime_filename(part, leafname);
987 if (code != CURLE_OK) {
992 if (mimetype == NULL) {
993 mimetype=strdup(
"text/plain");
995 if (mimetype == NULL) {
998 code = curl_mime_type(part, mimetype);
1000 if (code != CURLE_OK) {
1001 goto convert_failed;
1008 struct curl_mime_ctx *cb_ctx;
1009 cb_ctx = malloc(
sizeof(
struct curl_mime_ctx));
1010 if (cb_ctx == NULL) {
1011 goto convert_failed;
1013 cb_ctx->buffer = multipart->
value;
1014 cb_ctx->size = value_len;
1015 cb_ctx->position = 0;
1016 code = curl_mime_data_cb(part,
1018 mime_data_read_callback,
1019 mime_data_seek_callback,
1020 mime_data_free_callback,
1022 if (code != CURLE_OK) {
1024 goto convert_failed;
1032 NSLOG(netsurf, WARNING,
"postdata conversion failed with curl code: %d", code);
1033 curl_mime_free(cmime);
1043static struct curl_httppost *
1047 struct curl_httppost *post = NULL, *last = NULL;
1051 for (; control; control = control->
next) {
1052 if (control->
file) {
1053 char *leafname = NULL;
1063 if (control->
value[0] ==
'\0') {
1071 code = curl_formadd(&post, &last,
1072 CURLFORM_COPYNAME, control->
name,
1073 CURLFORM_BUFFER, control->
value,
1075 CURLFORM_FILENAME,
"",
1076 CURLFORM_BUFFERPTR, &buf,
1077 CURLFORM_BUFFERLENGTH, 0,
1078 CURLFORM_CONTENTTYPE,
1079 "application/octet-stream",
1081 if (code != CURL_FORMADD_OK)
1082 NSLOG(netsurf, INFO,
1083 "curl_formadd: %d (%s)", code,
1087 code = curl_formadd(&post, &last,
1088 CURLFORM_COPYNAME, control->
name,
1089 CURLFORM_FILE, control->
rawfile,
1090 CURLFORM_FILENAME, leafname,
1091 CURLFORM_CONTENTTYPE,
1092 (mimetype != 0 ? mimetype :
"text/plain"),
1094 if (code != CURL_FORMADD_OK)
1095 NSLOG(netsurf, INFO,
1096 "curl_formadd: %d (%s=%s)",
1104 code = curl_formadd(&post, &last,
1105 CURLFORM_COPYNAME, control->
name,
1106 CURLFORM_COPYCONTENTS, control->
value,
1108 if (code != CURL_FORMADD_OK)
1109 NSLOG(netsurf, INFO,
1110 "curl_formadd: %d (%s=%s)", code,
1125 CURLcode code = CURLE_OK;
1128#define SETOPT(option, value) { \
1129 code = curl_easy_setopt(f->curl_handle, option, value); \
1130 if (code != CURLE_OK) \
1136 SETOPT(CURLOPT_POSTFIELDS, NULL);
1138 SETOPT(CURLOPT_HTTPGET, 1L);
1143 SETOPT(CURLOPT_HTTPGET, 0L);
1148 SETOPT(CURLOPT_POSTFIELDS, NULL);
1149 SETOPT(CURLOPT_HTTPGET, 0L);
1173#define SETOPT(option, value) { \
1174 code = curl_easy_setopt(f->curl_handle, option, value); \
1175 if (code != CURLE_OK) \
1180 SETOPT(CURLOPT_PRIVATE, f);
1181 SETOPT(CURLOPT_WRITEDATA, f);
1182 SETOPT(CURLOPT_WRITEHEADER, f);
1186 if (code != CURLE_OK) {
1194 SETOPT(CURLOPT_COOKIE, NULL);
1198 SETOPT(CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
1199 SETOPT(CURLOPT_USERPWD, auth);
1201 SETOPT(CURLOPT_USERPWD, NULL);
1211#if LIBCURL_VERSION_NUM >= 0x071304
1218 SETOPT(CURLOPT_PROXYAUTH,
1221 (
long) CURLAUTH_BASIC :
1222 (
long) CURLAUTH_NTLM);
1231 SETOPT(CURLOPT_PROXY, NULL);
1236 SETOPT(CURLOPT_SSL_CIPHER_LIST,
1241 SETOPT(CURLOPT_SSL_SESSIONID_CACHE, 1);
1245 SETOPT(CURLOPT_SSL_VERIFYPEER, 0L);
1246 SETOPT(CURLOPT_SSL_VERIFYHOST, 0L);
1248 SETOPT(CURLOPT_SSL_CTX_FUNCTION, NULL);
1249 SETOPT(CURLOPT_SSL_CTX_DATA, NULL);
1253 SETOPT(CURLOPT_SSL_VERIFYPEER, 1L);
1254 SETOPT(CURLOPT_SSL_VERIFYHOST, 2L);
1257 SETOPT(CURLOPT_SSL_CTX_FUNCTION, fetch_curl_sslctxfun);
1258 SETOPT(CURLOPT_SSL_CTX_DATA, f);
1279 fetch->curl_handle = handle;
1283 if (code != CURLE_OK) {
1284 fetch->curl_handle = 0;
1286 NSLOG(netsurf, WARNING,
"cURL handle maybe went bad, retry later");
1287 curl_easy_cleanup(handle);
1293 assert(codem == CURLM_OK || codem == CURLM_CALL_MULTI_PERFORM);
1309 lwc_string_unref(h->
host);
1326 NSLOG(netsurf, DEBUG,
"Deferring fetch because we're inside cURL");
1338#if LIBCURL_VERSION_NUM >= 0x071e00
1340 curl_easy_cleanup(handle);
1348 curl_easy_cleanup(
handle);
1364 curl_easy_cleanup(h->
handle);
1366 lwc_string_unref(h->
host);
1370 curl_easy_cleanup(
handle);
1400 assert(codem == CURLM_OK);
1420 NSLOG(netsurf, DEBUG,
"Deferring cleanup");
1423 NSLOG(netsurf, DEBUG,
"Immediate abort");
1446 lwc_string_unref(f->
host);
1451 curl_slist_free_all(f->
headers);
1481 code = curl_easy_getinfo(f->
curl_handle, CURLINFO_HTTP_CODE,
1484 assert(code == CURLE_OK);
1537 bool finished =
false;
1542 char **_hideous_hack = (
char **) (
void *) &f;
1547 code = curl_easy_getinfo(
curl_handle, CURLINFO_PRIVATE, _hideous_hack);
1548 assert(code == CURLE_OK);
1550 abort_fetch = f->
abort;
1553 if ((abort_fetch ==
false) &&
1555 ((
result == CURLE_WRITE_ERROR) && (f->
stopped ==
false)))) {
1571 }
else if (
result == CURLE_PARTIAL_FILE) {
1586 }
else if (
result == CURLE_SSL_PEER_CERTIFICATE ||
1587 result == CURLE_SSL_CACERT) {
1594 NSLOG(netsurf, INFO,
"Unknown cURL response code %d",
result);
1606 }
else if (finished) {
1618 case CURLE_SSL_CONNECT_ERROR:
1622 case CURLE_OPERATION_TIMEDOUT:
1651 fd_set read_fd_set, write_fd_set, exc_fd_set;
1655 FD_ZERO(&read_fd_set);
1656 FD_ZERO(&write_fd_set);
1657 FD_ZERO(&exc_fd_set);
1660 &read_fd_set, &write_fd_set,
1661 &exc_fd_set, &max_fd);
1662 assert(codem == CURLM_OK);
1664 NSLOG(netsurf, DEEPDEBUG,
1665 "Curl file descriptor states (maxfd=%i):", max_fd);
1666 for (i = 0; i <= max_fd; i++) {
1671 if (FD_ISSET(i, &read_fd_set)) {
1674 if (FD_ISSET(i, &write_fd_set)) {
1677 if (FD_ISSET(i, &exc_fd_set)) {
1680 if (read || write || error) {
1681 NSLOG(netsurf, DEEPDEBUG,
" fd %i: %s %s %s", i,
1682 read ?
"read" :
" ",
1683 write ?
"write" :
" ",
1684 error ?
"error" :
" ");
1693 if (codem != CURLM_OK && codem != CURLM_CALL_MULTI_PERFORM) {
1694 NSLOG(netsurf, WARNING,
1695 "curl_multi_perform: %i %s",
1696 codem, curl_multi_strerror(codem));
1699 }
while (codem == CURLM_CALL_MULTI_PERFORM);
1704 switch (curl_msg->msg) {
1707 curl_msg->data.result);
1730 static char fetch_progress_buffer[256];
1732 uint64_t time_now_ms;
1743 nsu_getmonotonic_ms(&time_now_ms);
1744#define UPDATE_DELAY_MS (1000 / UPDATES_PER_SECOND)
1748#undef UPDATE_DELAY_MS
1752 snprintf(fetch_progress_buffer, 255,
1758 snprintf(fetch_progress_buffer, 255,
1778 static const char s_infotype[CURLINFO_END][3] = {
1779 "* ",
"< ",
"> ",
"{ ",
"} ",
"{ ",
"} "
1783 case CURLINFO_HEADER_OUT:
1784 case CURLINFO_HEADER_IN:
1785 NSLOG(
fetch, DEBUG,
"%s%.*s", s_infotype[
type], (
int)size - 1, data);
1796 curlsocktype purpose,
struct curl_sockaddr *address)
1802 address->family, address->socktype,
1824 code = curl_easy_getinfo(f->
curl_handle, CURLINFO_HTTP_CODE,
1827 assert(code == CURLE_OK);
1835 return size * nmemb;
1854 return size * nmemb;
1885#define SKIP_ST(o) for (i = (o); i < (int) size && (data[i] == ' ' || data[i] == '\t'); i++)
1887 if (12 < size && strncasecmp(data,
"Location:", 9) == 0) {
1892 NSLOG(netsurf, INFO,
"malloc failed");
1896 strncpy(f->
location, data + i, size - i);
1898 for (i = size - i - 1; i >= 0 &&
1904 }
else if (15 < size && strncasecmp(data,
"Content-Length:", 15) == 0) {
1907 if (i < (
int)size &&
'0' <= data[i] && data[i] <=
'9')
1909 }
else if (17 < size && strncasecmp(data,
"WWW-Authenticate:", 17) == 0) {
1913 while (i < (
int) size - 5 &&
1914 strncasecmp(data + i,
"realm", 5))
1916 while (i < (
int) size - 1 && data[++i] !=
'"')
1920 if (i < (
int) size) {
1923 while (end < size && data[end] !=
'"')
1928 f->
realm = malloc(end - i + 1);
1929 if (f->
realm != NULL) {
1930 strncpy(f->
realm, data + i, end - i);
1931 f->
realm[end - i] =
'\0';
1935 }
else if (11 < size && strncasecmp(data,
"Set-Cookie:", 11) == 0) {
1947 fd_set *write_set, fd_set *error_set)
1957 assert(code == CURLM_OK);
1968 curl_version_info_data *data;
1983#if LIBCURL_VERSION_NUM >= 0x073800
1987 setres = curl_global_sslset(CURLSSLBACKEND_OPENSSL, NULL, NULL);
1988 if (setres == CURLSSLSET_OK) {
1995 NSLOG(netsurf, INFO,
"curl_version %s", curl_version());
1997 code = curl_global_init(CURL_GLOBAL_ALL);
1998 if (code != CURLE_OK) {
1999 NSLOG(netsurf, INFO,
"curl_global_init failed.");
2005 NSLOG(netsurf, INFO,
"curl_multi_init failed.");
2009#if LIBCURL_VERSION_NUM >= 0x071e00
2017#define SETOPT(option, value) \
2018 mcode = curl_multi_setopt(fetch_curl_multi, option, value); \
2019 if (mcode != CURLM_OK) { \
2020 NSLOG(netsurf, ERROR, "attempting curl_multi_setopt(%s, ...)", #option); \
2021 goto curl_multi_setopt_failed; \
2024 SETOPT(CURLMOPT_MAXCONNECTS, maxconnects);
2025 SETOPT(CURLMOPT_MAX_TOTAL_CONNECTIONS, maxconnects);
2035 NSLOG(netsurf, INFO,
"curl_easy_init failed");
2040#define SETOPT(option, value) \
2041 code = curl_easy_setopt(fetch_blank_curl, option, value); \
2042 if (code != CURLE_OK) { \
2043 NSLOG(netsurf, ERROR, "attempting curl_easy_setopt(%s, ...)", #option); \
2044 goto curl_easy_setopt_failed; \
2050 SETOPT(CURLOPT_VERBOSE, 0);
2052 SETOPT(CURLOPT_VERBOSE, 1);
2056 SETOPT(CURLOPT_HTTP_VERSION, CURL_HTTP_VERSION_1_1);
2061 SETOPT(CURLOPT_NOPROGRESS, 0);
2063 SETOPT(CURLOPT_ENCODING,
"gzip");
2064 SETOPT(CURLOPT_LOW_SPEED_LIMIT, 1L);
2065 SETOPT(CURLOPT_LOW_SPEED_TIME, 180L);
2066 SETOPT(CURLOPT_NOSIGNAL, 1L);
2073 NSLOG(netsurf, INFO,
"ca_bundle: '%s'",
2082#if LIBCURL_VERSION_NUM < 0x073800
2088 if (code != CURLE_OK) {
2099#if LIBCURL_VERSION_NUM >= 0x073d00
2104 if (code != CURLE_OK && code != CURLE_NOT_BUILT_IN)
2105 goto curl_easy_setopt_failed;
2110 NSLOG(netsurf, INFO,
"cURL %slinked against openssl",
2115 data = curl_version_info(CURLVERSION_NOW);
2119 NSLOG(netsurf, CRITICAL,
"Unable to initialise SSL certificate hashmap");
2123 for (i = 0; data->protocols[i]; i++) {
2124 if (strcmp(data->protocols[i],
"http") == 0) {
2125 scheme = lwc_string_ref(corestring_lwc_http);
2127 }
else if (strcmp(data->protocols[i],
"https") == 0) {
2128 scheme = lwc_string_ref(corestring_lwc_https);
2136 NSLOG(netsurf, INFO,
2137 "Unable to register cURL fetcher for %s",
2138 data->protocols[i]);
2144curl_easy_setopt_failed:
2145 NSLOG(netsurf, INFO,
"curl_easy_setopt failed.");
2148#if LIBCURL_VERSION_NUM >= 0x071e00
2149curl_multi_setopt_failed:
2150 NSLOG(netsurf, INFO,
"curl_multi_setopt failed.");
static osspriteop_area * buffer
The buffer characteristics.
void fetch_set_http_code(struct fetch *fetch, long http_code)
set the http code of a fetch
void fetch_set_cookie(struct fetch *fetch, const char *data)
set cookie data on a fetch
nserror fetcher_add(lwc_string *scheme, const struct fetcher_operation_table *ops)
Register a fetcher for a scheme.
void fetch_send_callback(const fetch_msg *msg, struct fetch *fetch)
send message to fetch
void fetch_free(struct fetch *f)
Free a fetch structure and associated resources.
struct fetch_multipart_data * fetch_multipart_data_clone(const struct fetch_multipart_data *list)
Clone a linked list of fetch_multipart_data.
void fetch_remove_from_queues(struct fetch *fetch)
remove a queued fetch
void fetch_multipart_data_destroy(struct fetch_multipart_data *list)
Free a linked list of fetch_multipart_data.
Fetching of data from a URL (interface).
@ FETCH_POSTDATA_MULTIPART
Useful interned string pointers (interface).
#define CIPHER_SUITES
The ciphersuites the browser is prepared to use for TLS1.3.
static char fetch_proxy_userpwd[100]
Proxy authentication details.
static struct curl_fetch_info * fetch_alloc(void)
construct a new fetch structure
static bool fetch_curl_process_headers(struct curl_fetch_info *f)
Find the status code and content type and inform the caller.
CURLM * fetch_curl_multi
Global cURL multi handle.
static void curl_fetch_ssl_value_destroy(void *value)
static size_t fetch_curl_header(char *data, size_t size, size_t nmemb, void *_f)
Callback function for headers.
static bool inside_curl
Interlock to prevent initiation during callbacks.
#define NSCURL_PROGRESS_T
static CURLcode fetch_curl_set_options(struct curl_fetch_info *f)
Set options specific for a fetch.
static hashmap_t * curl_fetch_ssl_hashmap
static void * curl_fetch_ssl_value_alloc(void *key)
#define NSCURL_POSTDATA_T
static char fetch_error_buffer[CURL_ERROR_SIZE]
Error buffer for cURL.
static void fetch_curl_free(void *vf)
Free a fetch structure and associated resources.
#define APPEND(list, value)
#define CIPHER_LIST
The ciphersuites the browser is prepared to use for TLS<1.3.
static bool curl_with_openssl
Flag for runtime detection of openssl usage.
static bool fetch_curl_initiate_fetch(struct curl_fetch_info *fetch, CURL *handle)
Initiate a fetch from the queue.
static int fetch_curl_socket_close(void *clientp, curl_socket_t item)
static CURL * fetch_curl_get_handle(lwc_string *host)
Find a CURL handle to use to dispatch a job.
static void fetch_curl_cache_handle(CURL *handle, lwc_string *host)
Cache a CURL handle for the provided host (if wanted)
static void X509_free(X509 *cert)
static void fetch_curl_free_postdata(struct fetch_postdata *postdata)
free postdata
static int fetch_curl_debug(CURL *handle, curl_infotype type, char *data, size_t size, void *userptr)
Format curl debug for nslog.
static struct fetch_postdata * fetch_curl_alloc_postdata(const char *post_urlenc, const struct fetch_multipart_data *post_multipart)
allocate postdata
#define NSCURLOPT_PROGRESS_DATA
static void fetch_curl_abort(void *vf)
Abort a fetch.
static struct curl_httppost * fetch_curl_postdata_convert(CURL *chandle, const struct fetch_multipart_data *control)
Convert a list of struct fetch_multipart_data to a list of struct curl_httppost for libcurl.
static hashmap_parameters_t curl_fetch_ssl_hashmap_parameters
#define NSCURLOPT_PROGRESS_FUNCTION
static bool fetch_curl_start(void *vfetch)
Dispatch a single job.
static void fetch_curl_report_certs_upstream(struct curl_fetch_info *f)
Report the certificate information in the fetch to the users.
static void * fetch_curl_setup(struct fetch *parent_fetch, nsurl *url, bool only_2xx, bool downgrade_tls, const char *post_urlenc, const struct fetch_multipart_data *post_multipart, const char **headers)
Start fetching data for the given URL.
static CURL * fetch_blank_curl
Curl handle with default options set; not used for transfers.
static size_t fetch_curl_data(char *data, size_t size, size_t nmemb, void *_f)
Callback function for cURL.
static int curl_fetchers_registered
Count of how many schemes the curl fetcher is handling.
nserror fetch_curl_register(void)
Register curl scheme handler.
static void fetch_curl_stop(struct curl_fetch_info *f)
Clean up the provided fetch object and free it.
static int fetch_curl_fdset(lwc_string *scheme, fd_set *read_set, fd_set *write_set, fd_set *error_set)
#define NSCURL_POSTDATA_FREE(x)
static void fetch_curl_finalise(lwc_string *scheme)
Finalise a cURL fetcher.
static bool fetch_curl_can_fetch(const nsurl *url)
Check if this fetcher can fetch a url.
#define CIPHER_LIST_LEGACY
The legacy cipher suites the browser is prepared to use for TLS<1.3.
static CURLcode fetch_curl_set_postdata(struct curl_fetch_info *f)
Setup multipart post data.
static int fetch_curl_progress(void *clientp, NSCURL_PROGRESS_T dltotal, NSCURL_PROGRESS_T dlnow, NSCURL_PROGRESS_T ultotal, NSCURL_PROGRESS_T ulnow)
Callback function for fetch progress.
static bool curl_fetch_ssl_key_eq(void *key1, void *key2)
static bool fetch_curl_initialise(lwc_string *scheme)
Initialise a cURL fetcher.
static struct cache_handle * curl_handle_ring
Ring of cached handles.
static void fetch_curl_poll(lwc_string *scheme_ignored)
Do some work on current fetches.
#define SETOPT(option, value)
static void fetch_curl_done(CURL *curl_handle, CURLcode result)
Handle a completed fetch (CURLMSG_DONE from curl_multi_info_read()).
#define NSCURL_POSTDATA_CURLOPT
static uint32_t curl_fetch_ssl_key_hash(void *key)
static curl_socket_t fetch_curl_socket_open(void *clientp, curlsocktype purpose, struct curl_sockaddr *address)
Fetching of data from a URL (Registration).
nserror
Enumeration of error codes.
@ NSERROR_INIT_FAILED
Initialisation failed.
@ NSERROR_NOMEM
Memory exhaustion.
Interface for fetchers factory.
static nserror fetch(nsurl *url, enum backing_store_flags bsflags, uint8_t **data_out, size_t *datalen_out)
Retrieve an object from the backing store.
struct netsurf_table * guit
The global interface table.
Interface to core interface table.
bool hashmap_remove(hashmap_t *hashmap, void *key)
Remove an entry from the hashmap.
hashmap_t * hashmap_create(hashmap_parameters_t *params)
Create a hashmap.
void * hashmap_lookup(hashmap_t *hashmap, void *key)
Look up a key in a hashmap.
void * hashmap_insert(hashmap_t *hashmap, void *key)
Create an entry in a hashmap.
void hashmap_destroy(hashmap_t *hashmap)
Destroy a hashmap.
void(* hashmap_key_destroy_t)(void *)
Key destructor function type.
void *(* hashmap_key_clone_t)(void *)
Key cloning function type.
Interface to platform-specific fetcher operations.
Interface to platform-specific miscellaneous browser operation table.
internet structures and defines
Netsurf additional integer type formatting macros.
#define NSLOG(catname, level, logmsg, args...)
const char * messages_get(const char *key)
Fast lookup of a message by key from the standard Messages hash.
Localised message support (interface).
void nsurl_unref(nsurl *url)
Drop a reference to a NetSurf URL object.
const char * nsurl_access(const nsurl *url)
Access a NetSurf URL object as a string.
bool nsurl_has_component(const nsurl *url, nsurl_component part)
Enquire about the existence of componenets in a given URL.
nsurl * nsurl_ref(nsurl *url)
Increment the reference count to a NetSurf URL object.
lwc_string * nsurl_get_component(const nsurl *url, nsurl_component part)
Get part of a URL as a lwc_string, from a NetSurf URL object.
struct nsurl nsurl
NetSurf URL object.
#define RING_GETSIZE(ringtype, ring, sizevar)
Measure the size of a ring and put it in the supplied variable.
#define RING_FINDBYLWCHOST(ring, element, lwc_hostname)
Find the element (by hostname) in the given ring, leave it in the provided element variable.
#define RING_REMOVE(ring, element)
Remove the given element from the specified ring.
#define RING_INSERT(ring, element)
Insert the given item into the specified ring.
nserror cert_chain_alloc(size_t depth, struct cert_chain **chain_out)
create new certificate chain
@ SSL_CERT_ERR_TOO_YOUNG
This certificate is not yet valid.
@ SSL_CERT_ERR_BAD_SIG
Bad signature on this certificate.
@ SSL_CERT_ERR_BAD_ISSUER
Bad issuer.
@ SSL_CERT_ERR_SELF_SIGNED
This certificate (or the chain) is self signed.
@ SSL_CERT_ERR_OK
Nothing wrong with this certificate.
@ SSL_CERT_ERR_HOSTNAME_MISMATCH
This certificate host did not match the server.
@ SSL_CERT_ERR_TOO_OLD
This certificate is no longer valid.
@ SSL_CERT_ERR_REVOKED
This certificate has been revoked.
@ SSL_CERT_ERR_CHAIN_SELF_SIGNED
This certificate chain is self signed.
@ SSL_CERT_ERR_CERT_MISSING
This certificate was missing from the chain, its data is useless.
@ SSL_CERT_ERR_UNKNOWN
Unknown error.
nserror cert_chain_dup_into(const struct cert_chain *src, struct cert_chain *dst)
duplicate a certificate chain into an existing chain
nserror cert_chain_free(struct cert_chain *chain)
free a certificate chain
#define MAX_CERT_DEPTH
maximum number of X509 certificates in chain for TLS connection
Interface to utility string handling.
char * human_friendly_bytesize(unsigned long long int bytesize)
Create a human readable representation of a size in bytes.
CURL * handle
The cached cURL handle.
lwc_string * host
The host for which this handle is cached.
struct cache_handle * r_next
Next cached handle in ring.
struct cache_handle * r_prev
Previous cached handle in ring.
struct cert_chain::@57 certs[MAX_CERT_DEPTH]
size_t depth
the number of certificates in the chain
uint8_t * der
data in Distinguished Encoding Rules (DER) format
size_t der_length
DER length.
ssl_cert_err err
Whatever is wrong with this certificate.
X509 * cert
Pointer to certificate.
long err
OpenSSL error code.
Information for a single fetch.
struct fetch_postdata * postdata
POST data.
bool downgrade_tls
Downgrade to TLS 1.2.
char * realm
HTTP Auth Realm.
bool abort
Abort requested.
bool stopped
Download stopped on purpose.
bool sent_ssl_chain
Have we tried to send the SSL chain.
lwc_string * host
The hostname of this fetch.
int cert_depth
deepest certificate in use
struct curl_slist * headers
List of request headers.
long http_code
HTTP result code from cURL.
uint64_t last_progress_update
Time of last progress update.
nsurl * url
URL of this fetch.
char * cookie_string
Cookie string for this fetch.
unsigned long content_length
Response Content-Length, or 0.
bool only_2xx
Only HTTP 2xx responses acceptable.
CURL * curl_handle
cURL handle if being fetched, or 0.
struct fetch * fetch_handle
The fetch handle we're parented by.
NSCURL_POSTDATA_T * curl_postdata
POST data in curl representation.
char * location
Response Location header, or 0.
bool had_headers
Headers have been processed.
struct cert_info cert_data[MAX_CERT_DEPTH]
HTTPS certificate data.
struct fetch_msg::@118::@119 header_or_data
const struct cert_chain * chain
struct fetch_msg::@118::@120 auth
union fetch_msg::@118 data
Fetch POST multipart data.
char * rawfile
Raw filename if file is true.
struct fetch_multipart_data * next
Next in linked list.
struct fetch_multipart_data * multipart
Multipart post data if type is FETCH_POSTDATA_MULTIPART.
union fetch_postdata::@121 data
char * urlenc
Url encoded POST string if type is FETCH_POSTDATA_URLENC.
Information for a single fetch.
long http_code
HTTP response code, or 0.
lwc_string * host
Host part of URL, interned.
bool(* initialise)(lwc_string *scheme)
The initialiser for the fetcher.
char *(* mimetype)(const char *ro_path)
Find a MIME type for a local file.
int(* socket_close)(int socket)
Close a socket.
int(* socket_open)(int domain, int type, int protocol)
Open a socket.
nserror(* basename)(const char *path, char **str, size_t *size)
Get the basename of a file.
hashmap_key_clone_t key_clone
A function which when called will clone a key and give ownership of the returned object to the hashma...
The content of a hashmap.
struct gui_file_table * file
File table.
struct gui_fetch_table * fetch
Fetcher table.
Interface to time operations.
bool urldb_get_cert_permissions(nsurl *url)
Retrieve certificate verification permissions from database.
const char * urldb_get_auth_details(nsurl *url, const char *realm)
Look up authentication details in database.
char * urldb_get_cookie(nsurl *url, bool include_http_only)
Retrieve cookies for an URL.
Unified URL information database internal interface.
const char * user_agent_string(void)
Retrieve the core user agent for this release.
Default operations table for files.
Option reading and saving interface.
#define nsoption_charp(OPTION)
Get the value of a string option.
#define nsoption_int(OPTION)
Get the value of an integer option.
#define nsoption_uint(OPTION)
Get the value of an unsigned integer option.
@ OPTION_HTTP_PROXY_AUTH_NONE
@ OPTION_HTTP_PROXY_AUTH_BASIC
#define nsoption_bool(OPTION)
Get the value of a boolean option.
Interface to a number of general purpose functionality.