diff options
Diffstat (limited to 'content')
32 files changed, 1066 insertions, 575 deletions
diff --git a/content/fetch.h b/content/fetch.h index 843fec96e..e7180d0c3 100644 --- a/content/fetch.h +++ b/content/fetch.h @@ -94,6 +94,16 @@ typedef struct fetch_msg { } fetch_msg; /** + * Fetcher post data types + */ +typedef enum { + FETCH_POSTDATA_NONE, + FETCH_POSTDATA_URLENC, + FETCH_POSTDATA_MULTIPART, +} fetch_postdata_type; + + +/** * Fetch POST multipart data */ struct fetch_multipart_data { @@ -106,6 +116,20 @@ struct fetch_multipart_data { bool file; /**< Item is a file */ }; +/** + * fetch POST data + */ +struct fetch_postdata { + fetch_postdata_type type; + union { + /** Url encoded POST string if type is FETCH_POSTDATA_URLENC */ + char *urlenc; + /** Multipart post data if type is FETCH_POSTDATA_MULTIPART */ + struct fetch_multipart_data *multipart; + } data; +}; + + typedef void (*fetch_callback)(const fetch_msg *msg, void *p); /** diff --git a/content/fetchers/about/certificate.c b/content/fetchers/about/certificate.c index 554f06eb8..6f634d22a 100644 --- a/content/fetchers/about/certificate.c +++ b/content/fetchers/about/certificate.c @@ -134,26 +134,29 @@ static nserror free_ns_cert_info(struct ns_cert_info *cinfo) #include <openssl/ssl.h> #include <openssl/x509v3.h> -/* OpenSSL 1.0.x, 1.0.2, 1.1.0 and 1.1.1 API all changed - * LibreSSL declares its OpenSSL version as 2.1 but only supports 1.0.x API - */ -#if (defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x1010000fL)) -/* 1.0.x */ +#if (OPENSSL_VERSION_NUMBER < 0x30000000L) +/* OpenSSL 1.1.1 or LibreSSL */ + +# if defined(LIBRESSL_VERSION_NUMBER) + /* LibreSSL */ +# if (LIBRESSL_VERSION_NUMBER < 0x3050000fL) + /* LibreSSL <3.5.0 */ -#if (defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x1000200fL)) -/* pre 1.0.2 */ +# if (LIBRESSL_VERSION_NUMBER < 0x2070000fL) + /* LibreSSL <2.7.0 */ static int ns_X509_get_signature_nid(X509 *cert) { return OBJ_obj2nid(cert->cert_info->key->algor->algorithm); } -#else -#define ns_X509_get_signature_nid X509_get_signature_nid -#endif static const unsigned char *ns_ASN1_STRING_get0_data(ASN1_STRING *asn1str) { return (const unsigned char *)ASN1_STRING_data(asn1str); } +# else +# define ns_X509_get_signature_nid X509_get_signature_nid +# define ns_ASN1_STRING_get0_data ASN1_STRING_get0_data +# endif static const BIGNUM *ns_RSA_get0_n(const RSA *d) { @@ -164,298 +167,20 @@ static const BIGNUM *ns_RSA_get0_e(const RSA *d) { return d->e; } - -static int ns_EVP_PKEY_get_bn_param(const EVP_PKEY *pkey, - const char *key_name, BIGNUM **bn) { - RSA *rsa; - BIGNUM *result = NULL; - - /* Check parameters: only support allocation-form *bn */ - if (pkey == NULL || key_name == NULL || bn == NULL || *bn != NULL) - return 0; - - /* Only support RSA keys */ - if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) - return 0; - - rsa = EVP_PKEY_get1_RSA((EVP_PKEY *) pkey); - if (rsa == NULL) - return 0; - - if (strcmp(key_name, "n") == 0) { - const BIGNUM *n = ns_RSA_get0_n(rsa); - if (n != NULL) - result = BN_dup(n); - } else if (strcmp(key_name, "e") == 0) { - const BIGNUM *e = ns_RSA_get0_e(rsa); - if (e != NULL) - result = BN_dup(e); - } - - RSA_free(rsa); - - *bn = result; - - return (result != NULL) ? 1 : 0; -} - -static int ns_EVP_PKEY_get_utf8_string_param(const EVP_PKEY *pkey, - const char *key_name, char *str, size_t max_len, - size_t *out_len) -{ - const EC_GROUP *ecgroup; - const char *group; - EC_KEY *ec; - int ret = 0; - - if (pkey == NULL || key_name == NULL) - return 0; - - /* Only support EC keys */ - if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) - return 0; - - /* Only support fetching the group */ - if (strcmp(key_name, "group") != 0) - return 0; - - ec = EVP_PKEY_get1_EC_KEY((EVP_PKEY *) pkey); - - ecgroup = EC_KEY_get0_group(ec); - if (ecgroup == NULL) { - group = ""; - } else { - group = OBJ_nid2ln(EC_GROUP_get_curve_name(ecgroup)); - } - - if (str != NULL && max_len > strlen(group)) { - strcpy(str, group); - str[strlen(group)] = '\0'; - ret = 1; - } - if (out_len != NULL) - *out_len = strlen(group); - - EC_KEY_free(ec); - - return ret; -} - -static int ns_EVP_PKEY_get_octet_string_param(const EVP_PKEY *pkey, - const char *key_name, unsigned char *buf, size_t max_len, - size_t *out_len) -{ - const EC_GROUP *ecgroup; - const EC_POINT *ecpoint; - size_t len; - BN_CTX *bnctx; - EC_KEY *ec; - int ret = 0; - - if (pkey == NULL || key_name == NULL) - return 0; - - /* Only support EC keys */ - if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) - return 0; - - if (strcmp(key_name, "encoded-pub-key") != 0) - return 0; - - ec = EVP_PKEY_get1_EC_KEY((EVP_PKEY *) pkey); - if (ec == NULL) - return 0; - - ecgroup = EC_KEY_get0_group(ec); - if (ecgroup != NULL) { - ecpoint = EC_KEY_get0_public_key(ec); - if (ecpoint != NULL) { - bnctx = BN_CTX_new(); - len = EC_POINT_point2oct(ecgroup, - ecpoint, - POINT_CONVERSION_UNCOMPRESSED, - NULL, - 0, - bnctx); - if (len != 0 && len <= max_len) { - if (EC_POINT_point2oct(ecgroup, - ecpoint, - POINT_CONVERSION_UNCOMPRESSED, - buf, - len, - bnctx) == len) - ret = 1; - } - if (out_len != NULL) - *out_len = len; - BN_CTX_free(bnctx); - } - } - - EC_KEY_free(ec); - - return ret; -} -#elif (OPENSSL_VERSION_NUMBER < 0x1010100fL) -/* 1.1.0 */ -#define ns_X509_get_signature_nid X509_get_signature_nid -#define ns_ASN1_STRING_get0_data ASN1_STRING_get0_data - -static const BIGNUM *ns_RSA_get0_n(const RSA *r) -{ - const BIGNUM *n; - const BIGNUM *e; - const BIGNUM *d; - RSA_get0_key(r, &n, &e, &d); - return n; -} - -static const BIGNUM *ns_RSA_get0_e(const RSA *r) -{ - const BIGNUM *n; - const BIGNUM *e; - const BIGNUM *d; - RSA_get0_key(r, &n, &e, &d); - return e; -} - -static int ns_EVP_PKEY_get_bn_param(const EVP_PKEY *pkey, - const char *key_name, BIGNUM **bn) { - RSA *rsa; - BIGNUM *result = NULL; - - /* Check parameters: only support allocation-form *bn */ - if (pkey == NULL || key_name == NULL || bn == NULL || *bn != NULL) - return 0; - - /* Only support RSA keys */ - if (EVP_PKEY_base_id(pkey) != EVP_PKEY_RSA) - return 0; - - rsa = EVP_PKEY_get1_RSA((EVP_PKEY *) pkey); - if (rsa == NULL) - return 0; - - if (strcmp(key_name, "n") == 0) { - const BIGNUM *n = ns_RSA_get0_n(rsa); - if (n != NULL) - result = BN_dup(n); - } else if (strcmp(key_name, "e") == 0) { - const BIGNUM *e = ns_RSA_get0_e(rsa); - if (e != NULL) - result = BN_dup(e); - } - - RSA_free(rsa); - - *bn = result; - - return (result != NULL) ? 1 : 0; -} - -static int ns_EVP_PKEY_get_utf8_string_param(const EVP_PKEY *pkey, - const char *key_name, char *str, size_t max_len, - size_t *out_len) -{ - const EC_GROUP *ecgroup; - const char *group; - EC_KEY *ec; - int ret = 0; - - if (pkey == NULL || key_name == NULL) - return 0; - - /* Only support EC keys */ - if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) - return 0; - - /* Only support fetching the group */ - if (strcmp(key_name, "group") != 0) - return 0; - - ec = EVP_PKEY_get1_EC_KEY((EVP_PKEY *) pkey); - - ecgroup = EC_KEY_get0_group(ec); - if (ecgroup == NULL) { - group = ""; - } else { - group = OBJ_nid2ln(EC_GROUP_get_curve_name(ecgroup)); - } - - if (str != NULL && max_len > strlen(group)) { - strcpy(str, group); - str[strlen(group)] = '\0'; - ret = 1; - } - if (out_len != NULL) - *out_len = strlen(group); - - EC_KEY_free(ec); - - return ret; -} - -static int ns_EVP_PKEY_get_octet_string_param(const EVP_PKEY *pkey, - const char *key_name, unsigned char *buf, size_t max_len, - size_t *out_len) -{ - const EC_GROUP *ecgroup; - const EC_POINT *ecpoint; - size_t len; - BN_CTX *bnctx; - EC_KEY *ec; - int ret = 0; - - if (pkey == NULL || key_name == NULL) - return 0; - - /* Only support EC keys */ - if (EVP_PKEY_base_id(pkey) != EVP_PKEY_EC) - return 0; - - if (strcmp(key_name, "encoded-pub-key") != 0) - return 0; - - ec = EVP_PKEY_get1_EC_KEY((EVP_PKEY *) pkey); - if (ec == NULL) - return 0; - - ecgroup = EC_KEY_get0_group(ec); - if (ecgroup != NULL) { - ecpoint = EC_KEY_get0_public_key(ec); - if (ecpoint != NULL) { - bnctx = BN_CTX_new(); - len = EC_POINT_point2oct(ecgroup, - ecpoint, - POINT_CONVERSION_UNCOMPRESSED, - NULL, - 0, - bnctx); - if (len != 0 && len <= max_len) { - if (EC_POINT_point2oct(ecgroup, - ecpoint, - POINT_CONVERSION_UNCOMPRESSED, - buf, - len, - bnctx) == len) - ret = 1; - } - if (out_len != NULL) - *out_len = len; - BN_CTX_free(bnctx); - } - } - - EC_KEY_free(ec); - - return ret; -} -#elif (OPENSSL_VERSION_NUMBER < 0x30000000L) -/* 1.1.1 */ -#define ns_X509_get_signature_nid X509_get_signature_nid -#define ns_ASN1_STRING_get0_data ASN1_STRING_get0_data -#define ns_RSA_get0_n RSA_get0_n -#define ns_RSA_get0_e RSA_get0_e +# else + /* LibreSSL >= 3.5.0 */ +# define ns_X509_get_signature_nid X509_get_signature_nid +# define ns_ASN1_STRING_get0_data ASN1_STRING_get0_data +# define ns_RSA_get0_n RSA_get0_n +# define ns_RSA_get0_e RSA_get0_e +# endif +# else + /* OpenSSL 1.1.1 */ +# define ns_X509_get_signature_nid X509_get_signature_nid +# define ns_ASN1_STRING_get0_data ASN1_STRING_get0_data +# define ns_RSA_get0_n RSA_get0_n +# define ns_RSA_get0_e RSA_get0_e +# endif static int ns_EVP_PKEY_get_bn_param(const EVP_PKEY *pkey, const char *key_name, BIGNUM **bn) { @@ -589,7 +314,7 @@ static int ns_EVP_PKEY_get_octet_string_param(const EVP_PKEY *pkey, return ret; } #else -/* 3.x and later */ +/* OpenSSL 3.x and later */ #define ns_X509_get_signature_nid X509_get_signature_nid #define ns_ASN1_STRING_get0_data ASN1_STRING_get0_data #define ns_RSA_get0_n RSA_get0_n diff --git a/content/fetchers/curl.c b/content/fetchers/curl.c index a0c26ae25..680e60456 100644 --- a/content/fetchers/curl.c +++ b/content/fetchers/curl.c @@ -80,14 +80,25 @@ #define CIPHER_LIST \ /* disable everything */ \ "-ALL:" \ - /* enable TLSv1.2 PFS suites */ \ - "EECDH+AES+TLSv1.2:EDH+AES+TLSv1.2:" \ - /* enable PFS AES GCM suites */ \ - "EECDH+AESGCM:EDH+AESGCM:" \ - /* Enable PFS AES CBC suites */ \ - "EECDH+AES:EDH+AES:" \ - /* Remove any PFS suites using weak DSA key exchange */ \ - "-DSS" + /* enable TLSv1.2 ECDHE AES GCM suites */ \ + "EECDH+AESGCM+TLSv1.2:" \ + /* enable ECDHE CHACHA20/POLY1305 suites */ \ + "EECDH+CHACHA20:" \ + /* Sort above by strength */ \ + "@STRENGTH:" \ + /* enable ECDHE (auth=RSA, mac=SHA1) AES CBC suites */ \ + "EECDH+aRSA+AES+SHA1" + +/** + * The legacy cipher suites the browser is prepared to use for TLS<1.3 + */ +#define CIPHER_LIST_LEGACY \ + /* as above */ \ + CIPHER_LIST":" \ + /* enable (non-PFS) RSA AES GCM suites */ \ + "RSA+AESGCM:" \ + /* enable (non-PFS) RSA (mac=SHA1) AES CBC suites */ \ + "RSA+AES+SHA1" /* Open SSL compatability for certificate handling */ #ifdef WITH_OPENSSL @@ -95,33 +106,11 @@ #include <openssl/ssl.h> #include <openssl/x509v3.h> -/* OpenSSL 1.0.x to 1.1.0 certificate reference counting changed - * LibreSSL declares its OpenSSL version as 2.1 but only supports the old way - */ -#if (defined(LIBRESSL_VERSION_NUMBER) || (OPENSSL_VERSION_NUMBER < 0x1010000fL)) -static int ns_X509_up_ref(X509 *cert) -{ - cert->references++; - return 1; -} - -static void ns_X509_free(X509 *cert) -{ - cert->references--; - if (cert->references == 0) { - X509_free(cert); - } -} -#else -#define ns_X509_up_ref X509_up_ref -#define ns_X509_free X509_free -#endif - #else /* WITH_OPENSSL */ typedef char X509; -static void ns_X509_free(X509 *cert) +static void X509_free(X509 *cert) { free(cert); } @@ -222,6 +211,26 @@ struct cert_info { long err; /**< OpenSSL error code */ }; +#if LIBCURL_VERSION_NUM >= 0x072000 /* 7.32.0 depricated CURLOPT_PROGRESSFUNCTION*/ +#define NSCURLOPT_PROGRESS_FUNCTION CURLOPT_XFERINFOFUNCTION +#define NSCURLOPT_PROGRESS_DATA CURLOPT_XFERINFODATA +#define NSCURL_PROGRESS_T curl_off_t +#else +#define NSCURLOPT_PROGRESS_FUNCTION CURLOPT_PROGRESSFUNCTION +#define NSCURLOPT_PROGRESS_DATA CURLOPT_PROGRESSDATA +#define NSCURL_PROGRESS_T double +#endif + +#if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 depricated curl_formadd */ +#define NSCURL_POSTDATA_T curl_mime +#define NSCURL_POSTDATA_CURLOPT CURLOPT_MIMEPOST +#define NSCURL_POSTDATA_FREE(x) curl_mime_free(x) +#else +#define NSCURL_POSTDATA_T struct curl_httppost +#define NSCURL_POSTDATA_CURLOPT CURLOPT_HTTPPOST +#define NSCURL_POSTDATA_FREE(x) curl_formfree(x) +#endif + /** Information for a single fetch. */ struct curl_fetch_info { struct fetch *fetch_handle; /**< The fetch handle we're parented by. */ @@ -239,9 +248,11 @@ struct curl_fetch_info { unsigned long content_length; /**< Response Content-Length, or 0. */ char *cookie_string; /**< Cookie string for this fetch */ char *realm; /**< HTTP Auth Realm */ - char *post_urlenc; /**< Url encoded POST string, or 0. */ + struct fetch_postdata *postdata; /**< POST data */ + NSCURL_POSTDATA_T *curl_postdata; /**< POST data in curl representation */ + long http_code; /**< HTTP result code from cURL. */ - struct curl_httppost *post_multipart; /**< Multipart post data, or 0. */ + uint64_t last_progress_update; /**< Time of last progress update */ int cert_depth; /**< deepest certificate in use */ struct cert_info cert_data[MAX_CERT_DEPTH]; /**< HTTPS certificate data */ @@ -348,85 +359,95 @@ static bool fetch_curl_can_fetch(const nsurl *url) } + /** - * Convert a list of struct ::fetch_multipart_data to a list of - * struct curl_httppost for libcurl. + * allocate postdata */ -static struct curl_httppost * -fetch_curl_post_convert(const struct fetch_multipart_data *control) +static struct fetch_postdata * +fetch_curl_alloc_postdata(const char *post_urlenc, + const struct fetch_multipart_data *post_multipart) { - struct curl_httppost *post = 0, *last = 0; - CURLFORMcode code; - nserror ret; - - for (; control; control = control->next) { - if (control->file) { - char *leafname = NULL; - ret = guit->file->basename(control->value, &leafname, NULL); - if (ret != NSERROR_OK) { - continue; + struct fetch_postdata *postdata; + postdata = calloc(1, sizeof(struct fetch_postdata)); + if (postdata != NULL) { + + if (post_urlenc) { + postdata->type = FETCH_POSTDATA_URLENC; + postdata->data.urlenc = strdup(post_urlenc); + if (postdata->data.urlenc == NULL) { + free(postdata); + postdata = NULL; } - - /* We have to special case filenames of "", so curl - * a) actually attempts the fetch and - * b) doesn't attempt to open the file "" - */ - if (control->value[0] == '\0') { - /* dummy buffer - needs to be static so - * pointer's still valid when we go out - * of scope (not that libcurl should be - * attempting to access it, of course). - */ - static char buf; - - code = curl_formadd(&post, &last, - CURLFORM_COPYNAME, control->name, - CURLFORM_BUFFER, control->value, - /* needed, as basename("") == "." */ - CURLFORM_FILENAME, "", - CURLFORM_BUFFERPTR, &buf, - CURLFORM_BUFFERLENGTH, 0, - CURLFORM_CONTENTTYPE, - "application/octet-stream", - CURLFORM_END); - if (code != CURL_FORMADD_OK) - NSLOG(netsurf, INFO, - "curl_formadd: %d (%s)", code, - control->name); - } else { - char *mimetype = guit->fetch->mimetype(control->value); - code = curl_formadd(&post, &last, - CURLFORM_COPYNAME, control->name, - CURLFORM_FILE, control->rawfile, - CURLFORM_FILENAME, leafname, - CURLFORM_CONTENTTYPE, - (mimetype != 0 ? mimetype : "text/plain"), - CURLFORM_END); - if (code != CURL_FORMADD_OK) - NSLOG(netsurf, INFO, - "curl_formadd: %d (%s=%s)", - code, - control->name, - control->value); - free(mimetype); + } else if (post_multipart) { + postdata->type = FETCH_POSTDATA_MULTIPART; + postdata->data.multipart = fetch_multipart_data_clone(post_multipart); + if (postdata->data.multipart == NULL) { + free(postdata); + postdata = NULL; } - free(leafname); - } - else { - code = curl_formadd(&post, &last, - CURLFORM_COPYNAME, control->name, - CURLFORM_COPYCONTENTS, control->value, - CURLFORM_END); - if (code != CURL_FORMADD_OK) - NSLOG(netsurf, INFO, - "curl_formadd: %d (%s=%s)", code, - control->name, control->value); + } else { + postdata->type = FETCH_POSTDATA_NONE; } } + return postdata; +} - return post; +/** + * free postdata + */ +static void fetch_curl_free_postdata(struct fetch_postdata *postdata) +{ + if (postdata != NULL) { + switch (postdata->type) { + case FETCH_POSTDATA_NONE: + break; + case FETCH_POSTDATA_URLENC: + free(postdata->data.urlenc); + break; + case FETCH_POSTDATA_MULTIPART: + fetch_multipart_data_destroy(postdata->data.multipart); + break; + } + + free(postdata); + } } +/** + *construct a new fetch structure + */ +static struct curl_fetch_info *fetch_alloc(void) +{ + struct curl_fetch_info *fetch; + fetch = malloc(sizeof (*fetch)); + if (fetch == NULL) + return NULL; + + fetch->curl_handle = NULL; + fetch->sent_ssl_chain = false; + fetch->had_headers = false; + fetch->abort = false; + fetch->stopped = false; + fetch->only_2xx = false; + fetch->downgrade_tls = false; + fetch->headers = NULL; + fetch->url = NULL; + fetch->host = NULL; + fetch->location = NULL; + fetch->content_length = 0; + fetch->http_code = 0; + fetch->cookie_string = NULL; + fetch->realm = NULL; + fetch->last_progress_update = 0; + fetch->postdata = NULL; + fetch->curl_postdata = NULL; + + /* Clear certificate chain data */ + memset(fetch->cert_data, 0, sizeof(fetch->cert_data)); + fetch->cert_depth = -1; + + return fetch; +} /** * Start fetching data for the given URL. @@ -462,46 +483,22 @@ fetch_curl_setup(struct fetch *parent_fetch, struct curl_slist *slist; int i; - fetch = malloc(sizeof (*fetch)); + fetch = fetch_alloc(); if (fetch == NULL) - return 0; - - fetch->fetch_handle = parent_fetch; + return NULL; NSLOG(netsurf, INFO, "fetch %p, url '%s'", fetch, nsurl_access(url)); - /* construct a new fetch structure */ - fetch->curl_handle = NULL; - fetch->sent_ssl_chain = false; - fetch->had_headers = false; - fetch->abort = false; - fetch->stopped = false; fetch->only_2xx = only_2xx; fetch->downgrade_tls = downgrade_tls; - fetch->headers = NULL; + fetch->fetch_handle = parent_fetch; fetch->url = nsurl_ref(url); fetch->host = nsurl_get_component(url, NSURL_HOST); - fetch->location = NULL; - fetch->content_length = 0; - fetch->http_code = 0; - fetch->cookie_string = NULL; - fetch->realm = NULL; - fetch->post_urlenc = NULL; - fetch->post_multipart = NULL; - if (post_urlenc) { - fetch->post_urlenc = strdup(post_urlenc); - } else if (post_multipart) { - fetch->post_multipart = fetch_curl_post_convert(post_multipart); + if (fetch->host == NULL) { + goto failed; } - fetch->last_progress_update = 0; - - /* Clear certificate chain data */ - memset(fetch->cert_data, 0, sizeof(fetch->cert_data)); - fetch->cert_depth = -1; - - if ((fetch->host == NULL) || - (post_multipart != NULL && fetch->post_multipart == NULL) || - (post_urlenc != NULL && fetch->post_urlenc == NULL)) { + fetch->postdata = fetch_curl_alloc_postdata(post_urlenc, post_multipart); + if (fetch->postdata == NULL) { goto failed; } @@ -554,9 +551,7 @@ failed: lwc_string_unref(fetch->host); nsurl_unref(fetch->url); - free(fetch->post_urlenc); - if (fetch->post_multipart) - curl_formfree(fetch->post_multipart); + fetch_curl_free_postdata(fetch->postdata); curl_slist_free_all(fetch->headers); free(fetch); return NULL; @@ -736,7 +731,7 @@ fetch_curl_verify_callback(int verify_ok, X509_STORE_CTX *x509_ctx) */ if (!fetch->cert_data[depth].cert) { fetch->cert_data[depth].cert = X509_STORE_CTX_get_current_cert(x509_ctx); - ns_X509_up_ref(fetch->cert_data[depth].cert); + X509_up_ref(fetch->cert_data[depth].cert); fetch->cert_data[depth].err = X509_STORE_CTX_get_error(x509_ctx); } @@ -867,6 +862,301 @@ fetch_curl_report_certs_upstream(struct curl_fetch_info *f) f->sent_ssl_chain = true; } +#if LIBCURL_VERSION_NUM >= 0x073800 /* 7.56.0 depricated curl_formadd */ + +/** + * curl mime data context + */ +struct curl_mime_ctx { + char *buffer; + curl_off_t size; + curl_off_t position; +}; + +static size_t mime_data_read_callback(char *buffer, size_t size, size_t nitems, void *arg) +{ + struct curl_mime_ctx *mctx = (struct curl_mime_ctx *) arg; + curl_off_t sz = mctx->size - mctx->position; + + nitems *= size; + if(sz > (curl_off_t)nitems) { + sz = nitems; + } + if(sz) { + memcpy(buffer, mctx->buffer + mctx->position, sz); + } + mctx->position += sz; + return sz; +} + +static int mime_data_seek_callback(void *arg, curl_off_t offset, int origin) +{ + struct curl_mime_ctx *mctx = (struct curl_mime_ctx *) arg; + + switch(origin) { + case SEEK_END: + offset += mctx->size; + break; + case SEEK_CUR: + offset += mctx->position; + break; + } + + if(offset < 0) { + return CURL_SEEKFUNC_FAIL; + } + mctx->position = offset; + return CURL_SEEKFUNC_OK; +} + +static void mime_data_free_callback(void *arg) +{ + struct curl_mime_ctx *mctx = (struct curl_mime_ctx *) arg; + free(mctx); +} + +/** + * Convert a POST data list to a libcurl curl_mime. + * + * \param chandle curl fetch handle. + * \param multipart limked list of struct ::fetch_multipart forming post data. + */ +static curl_mime * +fetch_curl_postdata_convert(CURL *chandle, + const struct fetch_multipart_data *multipart) +{ + curl_mime *cmime; + curl_mimepart *part; + CURLcode code = CURLE_OK; + size_t value_len; + + cmime = curl_mime_init(chandle); + if (cmime == NULL) { + NSLOG(netsurf, WARNING, "postdata conversion failed to curl mime context"); + return NULL; + } + + /* iterate post data */ + for (; multipart != NULL; multipart = multipart->next) { + part = curl_mime_addpart(cmime); + if (part == NULL) { + goto convert_failed; + } + + code = curl_mime_name(part, multipart->name); + if (code != CURLE_OK) { + goto convert_failed; + } + + value_len = strlen(multipart->value); + + if (multipart->file && value_len==0) { + /* file entries with no filename require special handling */ + code=curl_mime_data(part, multipart->value, value_len); + if (code != CURLE_OK) { + goto convert_failed; + } + + code = curl_mime_filename(part, ""); + if (code != CURLE_OK) { + goto convert_failed; + } + + code = curl_mime_type(part, "application/octet-stream"); + if (code != CURLE_OK) { + goto convert_failed; + } + + } else if(multipart->file) { + /* file entry */ + nserror ret; + char *leafname = NULL; + char *mimetype = NULL; + + code = curl_mime_filedata(part, multipart->rawfile); + if (code != CURLE_OK) { + goto convert_failed; + } + + ret = guit->file->basename(multipart->value, &leafname, NULL); + if (ret != NSERROR_OK) { + goto convert_failed; + } + code = curl_mime_filename(part, leafname); + free(leafname); + if (code != CURLE_OK) { + goto convert_failed; + } + + mimetype = guit->fetch->mimetype(multipart->value); + if (mimetype == NULL) { + mimetype=strdup("text/plain"); + } + if (mimetype == NULL) { + goto convert_failed; + } + code = curl_mime_type(part, mimetype); + free(mimetype); + if (code != CURLE_OK) { + goto convert_failed; + } + + } else { + /* make the curl mime reference the existing multipart + * data which requires use of a callback and context. + */ + struct curl_mime_ctx *cb_ctx; + cb_ctx = malloc(sizeof(struct curl_mime_ctx)); + if (cb_ctx == NULL) { + goto convert_failed; + } + cb_ctx->buffer = multipart->value; + cb_ctx->size = value_len; + cb_ctx->position = 0; + code = curl_mime_data_cb(part, + value_len, + mime_data_read_callback, + mime_data_seek_callback, + mime_data_free_callback, + cb_ctx); + if (code != CURLE_OK) { + free(cb_ctx); + goto convert_failed; + } + } + } + + return cmime; + +convert_failed: + NSLOG(netsurf, WARNING, "postdata conversion failed with curl code: %d", code); + curl_mime_free(cmime); + return NULL; +} + +#else /* LIBCURL_VERSION_NUM >= 0x073800 */ + +/** + * Convert a list of struct ::fetch_multipart_data to a list of + * struct curl_httppost for libcurl. + */ +static struct curl_httppost * +fetch_curl_postdata_convert(CURL *chandle, + const struct fetch_multipart_data *control) +{ + struct curl_httppost *post = NULL, *last = NULL; + CURLFORMcode code; + nserror ret; + + for (; control; control = control->next) { + if (control->file) { + char *leafname = NULL; + ret = guit->file->basename(control->value, &leafname, NULL); + if (ret != NSERROR_OK) { + continue; + } + + /* We have to special case filenames of "", so curl + * a) actually attempts the fetch and + * b) doesn't attempt to open the file "" + */ + if (control->value[0] == '\0') { + /* dummy buffer - needs to be static so + * pointer's still valid when we go out + * of scope (not that libcurl should be + * attempting to access it, of course). + */ + static char buf; + + code = curl_formadd(&post, &last, + CURLFORM_COPYNAME, control->name, + CURLFORM_BUFFER, control->value, + /* needed, as basename("") == "." */ + CURLFORM_FILENAME, "", + CURLFORM_BUFFERPTR, &buf, + CURLFORM_BUFFERLENGTH, 0, + CURLFORM_CONTENTTYPE, + "application/octet-stream", + CURLFORM_END); + if (code != CURL_FORMADD_OK) + NSLOG(netsurf, INFO, + "curl_formadd: %d (%s)", code, + control->name); + } else { + char *mimetype = guit->fetch->mimetype(control->value); + code = curl_formadd(&post, &last, + CURLFORM_COPYNAME, control->name, + CURLFORM_FILE, control->rawfile, + CURLFORM_FILENAME, leafname, + CURLFORM_CONTENTTYPE, + (mimetype != 0 ? mimetype : "text/plain"), + CURLFORM_END); + if (code != CURL_FORMADD_OK) + NSLOG(netsurf, INFO, + "curl_formadd: %d (%s=%s)", + code, + control->name, + control->value); + free(mimetype); + } + free(leafname); + } else { + code = curl_formadd(&post, &last, + CURLFORM_COPYNAME, control->name, + CURLFORM_COPYCONTENTS, control->value, + CURLFORM_END); + if (code != CURL_FORMADD_OK) + NSLOG(netsurf, INFO, + "curl_formadd: %d (%s=%s)", code, + control->name, control->value); + } + } + + return post; +} + +#endif /* LIBCURL_VERSION_NUM >= 0x073800 */ + +/** + * Setup multipart post data + */ +static CURLcode fetch_curl_set_postdata(struct curl_fetch_info *f) +{ + CURLcode code = CURLE_OK; + +#undef SETOPT +#define SETOPT(option, value) { \ + code = curl_easy_setopt(f->curl_handle, option, value); \ + if (code != CURLE_OK) \ + return code; \ + } + + switch (f->postdata->type) { + case FETCH_POSTDATA_NONE: + SETOPT(CURLOPT_POSTFIELDS, NULL); + SETOPT(NSCURL_POSTDATA_CURLOPT, NULL); + SETOPT(CURLOPT_HTTPGET, 1L); + break; + + case FETCH_POSTDATA_URLENC: + SETOPT(NSCURL_POSTDATA_CURLOPT, NULL); + SETOPT(CURLOPT_HTTPGET, 0L); + SETOPT(CURLOPT_POSTFIELDS, f->postdata->data.urlenc); + break; + + case FETCH_POSTDATA_MULTIPART: + SETOPT(CURLOPT_POSTFIELDS, NULL); + SETOPT(CURLOPT_HTTPGET, 0L); + if (f->curl_postdata == NULL) { + f->curl_postdata = + fetch_curl_postdata_convert(f->curl_handle, + f->postdata->data.multipart); + } + SETOPT(NSCURL_POSTDATA_CURLOPT, f->curl_postdata); + break; + } + return code; +} /** * Set options specific for a fetch. @@ -890,20 +1180,11 @@ static CURLcode fetch_curl_set_options(struct curl_fetch_info *f) SETOPT(CURLOPT_PRIVATE, f); SETOPT(CURLOPT_WRITEDATA, f); SETOPT(CURLOPT_WRITEHEADER, f); - SETOPT(CURLOPT_PROGRESSDATA, f); + SETOPT(NSCURLOPT_PROGRESS_DATA, f); SETOPT(CURLOPT_HTTPHEADER, f->headers); - if (f->post_urlenc) { - SETOPT(CURLOPT_HTTPPOST, NULL); - SETOPT(CURLOPT_HTTPGET, 0L); - SETOPT(CURLOPT_POSTFIELDS, f->post_urlenc); - } else if (f->post_multipart) { - SETOPT(CURLOPT_POSTFIELDS, NULL); - SETOPT(CURLOPT_HTTPGET, 0L); - SETOPT(CURLOPT_HTTPPOST, f->post_multipart); - } else { - SETOPT(CURLOPT_POSTFIELDS, NULL); - SETOPT(CURLOPT_HTTPPOST, NULL); - SETOPT(CURLOPT_HTTPGET, 1L); + code = fetch_curl_set_postdata(f); + if (code != CURLE_OK) { + return code; } f->cookie_string = urldb_get_cookie(f->url, true); @@ -950,6 +1231,12 @@ static CURLcode fetch_curl_set_options(struct curl_fetch_info *f) SETOPT(CURLOPT_PROXY, NULL); } + + if (curl_with_openssl) { + SETOPT(CURLOPT_SSL_CIPHER_LIST, + f->downgrade_tls ? CIPHER_LIST_LEGACY : CIPHER_LIST); + } + /* Force-enable SSL session ID caching, as some distros are odd. */ SETOPT(CURLOPT_SSL_SESSIONID_CACHE, 1); @@ -1163,15 +1450,13 @@ static void fetch_curl_free(void *vf) if (f->headers) { curl_slist_free_all(f->headers); } - free(f->post_urlenc); - if (f->post_multipart) { - curl_formfree(f->post_multipart); - } + fetch_curl_free_postdata(f->postdata); + NSCURL_POSTDATA_FREE(f->curl_postdata); /* free certificate data */ for (i = 0; i < MAX_CERT_DEPTH; i++) { if (f->cert_data[i].cert != NULL) { - ns_X509_free(f->cert_data[i].cert); + X509_free(f->cert_data[i].cert); } } @@ -1201,7 +1486,7 @@ static bool fetch_curl_process_headers(struct curl_fetch_info *f) http_code = f->http_code; NSLOG(netsurf, INFO, "HTTP status code %li", http_code); - if (http_code == 304 && !f->post_urlenc && !f->post_multipart) { + if ((http_code == 304) && (f->postdata->type==FETCH_POSTDATA_NONE)) { /* Not Modified && GET request */ msg.type = FETCH_NOTMODIFIED; fetch_send_callback(&msg, f->fetch_handle); @@ -1437,10 +1722,10 @@ static void fetch_curl_poll(lwc_string *scheme_ignored) */ static int fetch_curl_progress(void *clientp, - double dltotal, - double dlnow, - double ultotal, - double ulnow) + NSCURL_PROGRESS_T dltotal, + NSCURL_PROGRESS_T dlnow, + NSCURL_PROGRESS_T ultotal, + NSCURL_PROGRESS_T ulnow) { static char fetch_progress_buffer[256]; /**< Progress buffer for cURL */ struct curl_fetch_info *f = (struct curl_fetch_info *) clientp; @@ -1507,6 +1792,24 @@ fetch_curl_debug(CURL *handle, } +static curl_socket_t fetch_curl_socket_open(void *clientp, + curlsocktype purpose, struct curl_sockaddr *address) +{ + (void) clientp; + (void) purpose; + + return (curl_socket_t) guit->fetch->socket_open( + address->family, address->socktype, + address->protocol); +} + +static int fetch_curl_socket_close(void *clientp, curl_socket_t item) +{ + (void) clientp; + + return guit->fetch->socket_close((int) item); +} + /** * Callback function for cURL. */ @@ -1754,7 +2057,7 @@ nserror fetch_curl_register(void) SETOPT(CURLOPT_WRITEFUNCTION, fetch_curl_data); SETOPT(CURLOPT_HEADERFUNCTION, fetch_curl_header); - SETOPT(CURLOPT_PROGRESSFUNCTION, fetch_curl_progress); + SETOPT(NSCURLOPT_PROGRESS_FUNCTION, fetch_curl_progress); SETOPT(CURLOPT_NOPROGRESS, 0); SETOPT(CURLOPT_USERAGENT, user_agent_string()); SETOPT(CURLOPT_ENCODING, "gzip"); @@ -1762,6 +2065,8 @@ nserror fetch_curl_register(void) SETOPT(CURLOPT_LOW_SPEED_TIME, 180L); SETOPT(CURLOPT_NOSIGNAL, 1L); SETOPT(CURLOPT_CONNECTTIMEOUT, nsoption_uint(curl_fetch_timeout)); + SETOPT(CURLOPT_OPENSOCKETFUNCTION, fetch_curl_socket_open); + SETOPT(CURLOPT_CLOSESOCKETFUNCTION, fetch_curl_socket_close); if (nsoption_charp(ca_bundle) && strcmp(nsoption_charp(ca_bundle), "")) { @@ -1792,8 +2097,12 @@ nserror fetch_curl_register(void) * fetch fails with "Unknown cipher in list" */ #if LIBCURL_VERSION_NUM >= 0x073d00 - /* Need libcurl 7.61.0 or later */ - SETOPT(CURLOPT_TLS13_CIPHERS, CIPHER_SUITES); + /* Need libcurl 7.61.0 or later built against OpenSSL with + * TLS1.3 support */ + code = curl_easy_setopt(fetch_blank_curl, + CURLOPT_TLS13_CIPHERS, CIPHER_SUITES); + if (code != CURLE_OK && code != CURLE_NOT_BUILT_IN) + goto curl_easy_setopt_failed; #endif SETOPT(CURLOPT_SSL_CIPHER_LIST, CIPHER_LIST); } diff --git a/content/fetchers/file/dirlist.c b/content/fetchers/file/dirlist.c index d49dc7fe7..345dbd8f3 100644 --- a/content/fetchers/file/dirlist.c +++ b/content/fetchers/file/dirlist.c @@ -29,6 +29,7 @@ #include "utils/messages.h" #include "utils/nscolour.h" +#include "netsurf/inttypes.h" #include "netsurf/types.h" #include "netsurf/plot_style.h" @@ -158,7 +159,7 @@ bool dirlist_generate_title(const char *title, char *buffer, int buffer_length) "<title>%s</title>\n" "<style>\n" "html {\n" - "\tbackground-color: #%06x;\n" + "\tbackground-color: #%06"PRIx32";\n" "}\n" "%s" "</style>\n" diff --git a/content/fs_backing_store.c b/content/fs_backing_store.c index ede729f9a..a145c6fe1 100644 --- a/content/fs_backing_store.c +++ b/content/fs_backing_store.c @@ -89,14 +89,6 @@ #define BLOCK_USE_MAP_SIZE (1 << (BLOCK_ENTRY_COUNT - 3)) /** - * The type used to store index values referring to store entries. Care - * must be taken with this type as it is used to build address to - * entry mapping so changing the size will have large impacts on - * memory usage. - */ -typedef uint16_t entry_index_t; - -/** * The type used as a binary identifier for each entry derived from * the URL. A larger identifier will have fewer collisions but * requires proportionately more storage. @@ -1614,7 +1606,7 @@ static nserror store_write_block(struct store_state *state, offst); if (wr != (ssize_t)bse->elem[elem_idx].size) { NSLOG(netsurf, ERROR, - "Write failed %"PRIssizet" of %d bytes from %p at %"PRIsizet" block %d errno %d", + "Write failed %"PRIssizet" of %"PRId32" bytes from %p at %"PRIsizet" block %"PRIu16" errno %d", wr, bse->elem[elem_idx].size, bse->elem[elem_idx].data, @@ -1661,7 +1653,7 @@ static nserror store_write_file(struct store_state *state, close(fd); if (wr != (ssize_t)bse->elem[elem_idx].size) { NSLOG(netsurf, ERROR, - "Write failed %"PRIssizet" of %d bytes from %p errno %d", + "Write failed %"PRIssizet" of %"PRId32" bytes from %p errno %d", wr, bse->elem[elem_idx].size, bse->elem[elem_idx].data, @@ -1784,7 +1776,7 @@ static nserror store_read_block(struct store_state *state, offst); if (rd != (ssize_t)bse->elem[elem_idx].size) { NSLOG(netsurf, ERROR, - "Failed reading %"PRIssizet" of %d bytes into %p from %"PRIsizet" block %d errno %d", + "Failed reading %"PRIssizet" of %"PRId32" bytes into %p from %"PRIsizet" block %"PRIu16" errno %d", rd, bse->elem[elem_idx].size, bse->elem[elem_idx].data, diff --git a/content/handlers/css/dump.c b/content/handlers/css/dump.c index 4138f9343..950a6f8cc 100644 --- a/content/handlers/css/dump.c +++ b/content/handlers/css/dump.c @@ -19,6 +19,8 @@ #include <stdio.h> #include <libcss/libcss.h> +#include "netsurf/inttypes.h" + #include "css/dump.h" #include "css/utils.h" @@ -36,7 +38,7 @@ static void dump_css_fixed(FILE *stream, css_fixed f) uint32_t fracpart = ((NSCSS_ABS(f) & 0x3ff) * 1000 + 500) / (1 << 10); #undef NSCSS_ABS - fprintf(stream, "%s%d.%03d", f < 0 ? "-" : "", uintpart, fracpart); + fprintf(stream, "%s%"PRIu32".%03"PRIu32, f < 0 ? "-" : "", uintpart, fracpart); } /** @@ -48,7 +50,7 @@ static void dump_css_fixed(FILE *stream, css_fixed f) static void dump_css_number(FILE *stream, css_fixed val) { if (INTTOFIX(FIXTOINT(val)) == val) - fprintf(stream, "%d", FIXTOINT(val)); + fprintf(stream, "%"PRId32, FIXTOINT(val)); else dump_css_fixed(stream, val); } @@ -181,7 +183,7 @@ void nscss_dump_computed_style(FILE *stream, const css_computed_style *style) val = css_computed_background_color(style, &color); switch (val) { case CSS_BACKGROUND_COLOR_COLOR: - fprintf(stream, "background-color: #%08x ", color); + fprintf(stream, "background-color: #%08"PRIx32" ", color); break; default: break; @@ -255,7 +257,7 @@ void nscss_dump_computed_style(FILE *stream, const css_computed_style *style) val = css_computed_border_top_color(style, &color); switch (val) { case CSS_BORDER_COLOR_COLOR: - fprintf(stream, "border-top-color: #%08x ", color); + fprintf(stream, "border-top-color: #%08"PRIx32" ", color); break; default: break; @@ -265,7 +267,7 @@ void nscss_dump_computed_style(FILE *stream, const css_computed_style *style) val = css_computed_border_right_color(style, &color); switch (val) { case CSS_BORDER_COLOR_COLOR: - fprintf(stream, "border-right-color: #%08x ", color); + fprintf(stream, "border-right-color: #%08"PRIx32" ", color); break; default: break; @@ -275,7 +277,7 @@ void nscss_dump_computed_style(FILE *stream, const css_computed_style *style) val = css_computed_border_bottom_color(style, &color); switch (val) { case CSS_BORDER_COLOR_COLOR: - fprintf(stream, "border-bottom-color: #%08x ", color); + fprintf(stream, "border-bottom-color: #%08"PRIx32" ", color); break; default: break; @@ -285,7 +287,7 @@ void nscss_dump_computed_style(FILE *stream, const css_computed_style *style) val = css_computed_border_left_color(style, &color); switch (val) { case CSS_BORDER_COLOR_COLOR: - fprintf(stream, "border-left-color: #%08x ", color); + fprintf(stream, "border-left-color: #%08"PRIx32" ", color); break; default: break; @@ -610,7 +612,7 @@ void nscss_dump_computed_style(FILE *stream, const css_computed_style *style) /* color */ val = css_computed_color(style, &color); if (val == CSS_COLOR_COLOR) { - fprintf(stream, "color: #%08x ", color); + fprintf(stream, "color: #%08"PRIx32" ", color); } /* content */ @@ -1353,7 +1355,7 @@ void nscss_dump_computed_style(FILE *stream, const css_computed_style *style) fprintf(stream, "outline-color: invert "); break; case CSS_OUTLINE_COLOR_COLOR: - fprintf(stream, "outline-color: #%08x ", color); + fprintf(stream, "outline-color: #%08"PRIx32" ", color); break; default: break; @@ -1820,7 +1822,7 @@ void nscss_dump_computed_style(FILE *stream, const css_computed_style *style) fprintf(stream, "z-index: auto "); break; case CSS_Z_INDEX_SET: - fprintf(stream, "z-index: %d ", zindex); + fprintf(stream, "z-index: %"PRId32" ", zindex); break; default: break; diff --git a/content/handlers/css/hints.c b/content/handlers/css/hints.c index defeae10a..0f246a64c 100644 --- a/content/handlers/css/hints.c +++ b/content/handlers/css/hints.c @@ -1624,13 +1624,19 @@ static void css_hint_list( } -/* Exported function, documeted in css/hints.h */ +/* Exported function, documented in css/hints.h */ css_error node_presentational_hint(void *pw, void *node, uint32_t *nhints, css_hint **hints) { dom_exception exc; dom_html_element_type tag_type; + if (nsoption_bool(author_level_css) == false) { + *nhints = 0; + *hints = NULL; + return CSS_OK; + } + css_hint_clean(); exc = dom_html_element_get_tag_type(node, &tag_type); @@ -1644,22 +1650,22 @@ css_error node_presentational_hint(void *pw, void *node, css_hint_width(pw, node); css_hint_table_cell_border_padding(pw, node); css_hint_white_space_nowrap(pw, node); - /* fall through */ + fallthrough; case DOM_HTML_ELEMENT_TYPE_TR: css_hint_height(pw, node); - /* fall through */ + fallthrough; case DOM_HTML_ELEMENT_TYPE_THEAD: case DOM_HTML_ELEMENT_TYPE_TBODY: case DOM_HTML_ELEMENT_TYPE_TFOOT: css_hint_text_align_special(pw, node); - /* fall through */ + fallthrough; case DOM_HTML_ELEMENT_TYPE_COL: css_hint_vertical_align_table_cells(pw, node); break; case DOM_HTML_ELEMENT_TYPE_APPLET: case DOM_HTML_ELEMENT_TYPE_IMG: css_hint_margin_hspace_vspace(pw, node); - /* fall through */ + fallthrough; case DOM_HTML_ELEMENT_TYPE_EMBED: case DOM_HTML_ELEMENT_TYPE_IFRAME: case DOM_HTML_ELEMENT_TYPE_OBJECT: @@ -1682,7 +1688,7 @@ css_error node_presentational_hint(void *pw, void *node, break; case DOM_HTML_ELEMENT_TYPE_CAPTION: css_hint_caption_side(pw, node); - /* fall through */ + fallthrough; case DOM_HTML_ELEMENT_TYPE_DIV: css_hint_text_align_special(pw, node); break; diff --git a/content/handlers/html/box_construct.c b/content/handlers/html/box_construct.c index eeadb8453..8519c2b1d 100644 --- a/content/handlers/html/box_construct.c +++ b/content/handlers/html/box_construct.c @@ -249,16 +249,19 @@ box_get_style(html_content *c, const css_computed_style *root_style, dom_node *n) { - dom_string *s; - dom_exception err; + dom_string *s = NULL; css_stylesheet *inline_style = NULL; css_select_results *styles; nscss_select_ctx ctx; /* Firstly, construct inline stylesheet, if any */ - err = dom_element_get_attribute(n, corestring_dom_style, &s); - if (err != DOM_NO_ERR) - return NULL; + if (nsoption_bool(author_level_css)) { + dom_exception err; + err = dom_element_get_attribute(n, corestring_dom_style, &s); + if (err != DOM_NO_ERR) { + return NULL; + } + } if (s != NULL) { inline_style = nscss_create_inline_style( diff --git a/content/handlers/html/box_inspect.c b/content/handlers/html/box_inspect.c index 181f58cf8..6591b6446 100644 --- a/content/handlers/html/box_inspect.c +++ b/content/handlers/html/box_inspect.c @@ -25,6 +25,7 @@ #include <stdio.h> #include <dom/dom.h> +#include "utils/utils.h" #include "utils/nsurl.h" #include "utils/errors.h" #include "netsurf/types.h" @@ -212,7 +213,7 @@ box_move_xy(struct box *b, enum box_walk_dir dir, int *x, int *y) rb = b; break; } - /* fall through */ + fallthrough; case BOX_WALK_NEXT_SIBLING: do { diff --git a/content/handlers/html/css.c b/content/handlers/html/css.c index 2434b1783..0bc38844f 100644 --- a/content/handlers/html/css.c +++ b/content/handlers/html/css.c @@ -33,6 +33,7 @@ #include "utils/nsoption.h" #include "utils/corestrings.h" #include "utils/log.h" +#include "netsurf/inttypes.h" #include "netsurf/misc.h" #include "netsurf/content.h" #include "content/hlcache.h" @@ -173,7 +174,7 @@ html_stylesheet_from_domnode(html_content *c, dom_string_unref(style); - snprintf(urlbuf, sizeof(urlbuf), "x-ns-css:%u", key); + snprintf(urlbuf, sizeof(urlbuf), "x-ns-css:%"PRIu32"", key); error = nsurl_create(urlbuf, &url); if (error != NSERROR_OK) { @@ -395,16 +396,20 @@ bool html_css_process_link(html_content *htmlc, dom_node *node) if (exc != DOM_NO_ERR || rel == NULL) return true; - if (strcasestr(dom_string_data(rel), "stylesheet") == 0) { + if (strcasestr(dom_string_data(rel), "stylesheet") == NULL) { dom_string_unref(rel); return true; - } else if (strcasestr(dom_string_data(rel), "alternate") != 0) { + } else if (strcasestr(dom_string_data(rel), "alternate") != NULL) { /* Ignore alternate stylesheets */ dom_string_unref(rel); return true; } dom_string_unref(rel); + if (nsoption_bool(author_level_css) == false) { + return true; + } + /* type='text/css' or not present */ exc = dom_element_get_attribute(node, corestring_dom_type, &type_attr); if (exc == DOM_NO_ERR && type_attr != NULL) { diff --git a/content/handlers/html/dom_event.c b/content/handlers/html/dom_event.c index 36a020b6d..d42882515 100644 --- a/content/handlers/html/dom_event.c +++ b/content/handlers/html/dom_event.c @@ -25,6 +25,7 @@ #include <string.h> #include "utils/config.h" +#include "utils/utils.h" #include "utils/corestrings.h" #include "utils/nsoption.h" #include "utils/log.h" @@ -622,7 +623,9 @@ dom_default_action_DOMNodeInserted_cb(struct dom_event *evt, void *pw) break; case DOM_HTML_ELEMENT_TYPE_STYLE: - html_css_process_style(htmlc, (dom_node *)node); + if (nsoption_bool(author_level_css)) { + html_css_process_style(htmlc, (dom_node *)node); + } break; case DOM_HTML_ELEMENT_TYPE_SCRIPT: @@ -689,6 +692,7 @@ dom_default_action_DOMNodeInsertedIntoDocument_cb(struct dom_event *evt, switch (tag_type) { case DOM_HTML_ELEMENT_TYPE_SCRIPT: dom_SCRIPT_showed_up(htmlc, (dom_html_script_element *) node); + fallthrough; default: break; } @@ -730,11 +734,15 @@ dom_default_action_DOMSubtreeModified_cb(struct dom_event *evt, void *pw) switch (tag_type) { case DOM_HTML_ELEMENT_TYPE_STYLE: - html_css_update_style(htmlc, (dom_node *)node); + if (nsoption_bool(author_level_css)) { + html_css_update_style(htmlc, + (dom_node *)node); + } break; case DOM_HTML_ELEMENT_TYPE_TEXTAREA: case DOM_HTML_ELEMENT_TYPE_INPUT: html_texty_element_update(htmlc, (dom_node *)node); + fallthrough; default: break; } diff --git a/content/handlers/html/form.c b/content/handlers/html/form.c index 97ec19518..9b6768a56 100644 --- a/content/handlers/html/form.c +++ b/content/handlers/html/form.c @@ -41,6 +41,7 @@ #include "utils/utf8.h" #include "utils/ascii.h" #include "netsurf/browser_window.h" +#include "netsurf/inttypes.h" #include "netsurf/mouse.h" #include "netsurf/plotters.h" #include "netsurf/misc.h" @@ -486,7 +487,7 @@ form_dom_to_data_select(dom_html_select_element *select_element, &option_element); if (exp != DOM_NO_ERR) { NSLOG(netsurf, INFO, - "Could not get options item %d", option_index); + "Could not get options item %"PRId32, option_index); res = NSERROR_DOM; } else { res = form_dom_to_data_select_option( @@ -1100,7 +1101,7 @@ form_dom_to_data(struct form *form, exp = dom_html_collection_item(elements, element_idx, &element); if (exp != DOM_NO_ERR) { NSLOG(netsurf, INFO, - "retrieving form element %d failed with %d", + "retrieving form element %"PRIu32" failed with %d", element_idx, exp); res = NSERROR_DOM; goto form_dom_to_data_error; @@ -1110,7 +1111,7 @@ form_dom_to_data(struct form *form, exp = dom_node_get_node_name(element, &nodename); if (exp != DOM_NO_ERR) { NSLOG(netsurf, INFO, - "getting element node name %d failed with %d", + "getting element node name %"PRIu32" failed with %d", element_idx, exp); dom_node_unref(element); res = NSERROR_DOM; @@ -2001,15 +2002,33 @@ void form_radio_set(struct form_control *radio) if (radio->selected) return; - for (control = radio->form->controls; control; - control = control->next) { + /* Clear selected state for other controls in + * the same radio button group */ + for (control = radio->form->controls; + control != NULL; + control = control->next) { + /* Only interested in radio inputs */ if (control->type != GADGET_RADIO) continue; + + /* Ignore ourself */ if (control == radio) continue; - if (strcmp(control->name, radio->name) != 0) + + /* Ignore inputs where: + * a) this or the other control have no name attribute + * b) this or the other control have an empty name attribute + * c) the control names do not match + */ + if ((control->name == NULL) || + (radio->name == NULL) || + (control->name[0] == '\0') || + (radio->name[0] == '\0') || + strcmp(control->name, radio->name) != 0) continue; + /* Other control is in the same radio button group: clear its + * selected state */ if (control->selected) { control->selected = false; dom_html_input_element_set_checked(control->node, false); diff --git a/content/handlers/html/html.c b/content/handlers/html/html.c index 2b6b1a865..82f5f1388 100644 --- a/content/handlers/html/html.c +++ b/content/handlers/html/html.c @@ -123,7 +123,7 @@ bool fire_generic_dom_event(dom_string *type, dom_node *target, return false; } NSLOG(netsurf, INFO, "Dispatching '%*s' against %p", - dom_string_length(type), dom_string_data(type), target); + (int)dom_string_length(type), dom_string_data(type), target); result = fire_dom_event(evt, target); dom_event_unref(evt); return result; @@ -200,7 +200,7 @@ bool fire_dom_keyboard_event(dom_string *type, dom_node *target, } NSLOG(netsurf, INFO, "Dispatching '%*s' against %p", - dom_string_length(type), dom_string_data(type), target); + (int)dom_string_length(type), dom_string_data(type), target); result = fire_dom_event((dom_event *) evt, target); dom_event_unref(evt); diff --git a/content/handlers/html/interaction.c b/content/handlers/html/interaction.c index 026ef1ee7..0a843e026 100644 --- a/content/handlers/html/interaction.c +++ b/content/handlers/html/interaction.c @@ -899,7 +899,7 @@ gadget_mouse_action(html_content *html, } free(oldcoords); } - /* Fall through */ + fallthrough; case GADGET_SUBMIT: if (mas->gadget.control->form) { @@ -1465,7 +1465,7 @@ html_mouse_action(struct content *c, int x, int y) { html_content *html = (html_content *)c; - nserror res; + nserror res = NSERROR_OK; /* handle open select menu */ if (html->visible_select_menu != NULL) { @@ -1493,7 +1493,7 @@ html_mouse_action(struct content *c, break; case HTML_DRAG_NONE: - res = mouse_action_drag_none(html, bw, mouse, x, y); + res = mouse_action_drag_none(html, bw, mouse, x, y); break; default: @@ -1669,7 +1669,7 @@ void html_set_drag_type(html_content *html, html_drag_type drag_type, case HTML_DRAG_SELECTION: assert(drag_owner.no_owner == true); - /* Fall through */ + fallthrough; case HTML_DRAG_TEXTAREA_SELECTION: case HTML_DRAG_CONTENT_SELECTION: msg_data.drag.type = CONTENT_DRAG_SELECTION; @@ -1800,7 +1800,7 @@ void html_set_selection(html_content *html, html_selection_type selection_type, break; case HTML_SELECTION_SELF: assert(selection_owner.none == false); - /* fall through */ + fallthrough; case HTML_SELECTION_TEXTAREA: case HTML_SELECTION_CONTENT: msg_data.selection.selection = true; diff --git a/content/handlers/html/layout.c b/content/handlers/html/layout.c index d9de14b37..76ce24df5 100644 --- a/content/handlers/html/layout.c +++ b/content/handlers/html/layout.c @@ -2305,7 +2305,7 @@ static bool layout_block_object(struct box *block) NSLOG(layout, DEBUG, "block %p, object %p, width %i", block, hlcache_handle_get_url(block->object), block->width); - if (content_get_type(block->object) == CONTENT_HTML) { + if (content_can_reformat(block->object)) { content_reformat(block->object, false, block->width, 1); } else { /* Non-HTML objects */ @@ -2984,7 +2984,7 @@ layout_line(struct box *first, } /* Reformat object to new box size */ - if (b->object && content_get_type(b->object) == CONTENT_HTML && + if (b->object && content_can_reformat(b->object) && b->width != content_get_available_width(b->object)) { css_fixed value = 0; @@ -4194,7 +4194,7 @@ layout__get_ol_reversed(dom_node *ol_node) */ static bool layout__get_list_item_count( - dom_node *list_owner, int *count_out) + dom_node *list_owner, dom_long *count_out) { dom_html_element_type tag_type; dom_exception exc; @@ -4266,7 +4266,7 @@ layout__ordered_list_count( dom_exception exc; dom_node *child; int step = 1; - int next; + dom_long next; if (box->node == NULL) { return; diff --git a/content/handlers/html/layout_flex.c b/content/handlers/html/layout_flex.c index 61adcaa6c..bde3c5bd1 100644 --- a/content/handlers/html/layout_flex.c +++ b/content/handlers/html/layout_flex.c @@ -960,7 +960,6 @@ static void layout_flex__place_line_items_cross(struct flex_ctx *ctx, switch (lh__box_align_self(ctx->flex, b)) { default: - /* Fall through. */ case CSS_ALIGN_SELF_STRETCH: if (lh__box_size_cross_is_auto(ctx->horizontal, b)) { *box_size_cross += cross_free_space; @@ -970,7 +969,7 @@ static void layout_flex__place_line_items_cross(struct flex_ctx *ctx, return; } } - /* Fall through. */ + fallthrough; case CSS_ALIGN_SELF_FLEX_START: *box_pos_cross = ctx->flex->padding[cross_start] + line->pos + @@ -986,7 +985,6 @@ static void layout_flex__place_line_items_cross(struct flex_ctx *ctx, break; case CSS_ALIGN_SELF_BASELINE: - /* Fall through. */ case CSS_ALIGN_SELF_CENTER: *box_pos_cross = ctx->flex->padding[cross_start] + line->pos + cross_free_space / 2 + diff --git a/content/handlers/html/redraw_border.c b/content/handlers/html/redraw_border.c index 39ed432cd..3a1f6f308 100644 --- a/content/handlers/html/redraw_border.c +++ b/content/handlers/html/redraw_border.c @@ -25,6 +25,7 @@ #include <stdbool.h> #include <stdlib.h> +#include "utils/utils.h" #include "utils/log.h" #include "netsurf/plotters.h" #include "netsurf/css.h" @@ -121,7 +122,7 @@ html_redraw_border_plot(const int side, switch (style) { case CSS_BORDER_STYLE_DOTTED: plot_style_bdr.stroke_type = PLOT_OP_TYPE_DOT; - /* fall through */ + fallthrough; case CSS_BORDER_STYLE_DASHED: rect.x0 = (p[0] + p[2]) / 2; rect.y0 = (p[1] + p[3]) / 2; @@ -131,7 +132,7 @@ html_redraw_border_plot(const int side, break; case CSS_BORDER_STYLE_SOLID: - /* fall through to default */ + /* solid is the default */ default: if (rectangular || thickness == 1) { @@ -190,7 +191,7 @@ html_redraw_border_plot(const int side, case CSS_BORDER_STYLE_GROOVE: light = 3 - light; - /* fall through */ + fallthrough; case CSS_BORDER_STYLE_RIDGE: /* choose correct colours for each part of the border line */ if (light <= 1) { @@ -300,7 +301,7 @@ html_redraw_border_plot(const int side, case CSS_BORDER_STYLE_INSET: light = (light + 2) % 4; - /* fall through */ + fallthrough; case CSS_BORDER_STYLE_OUTSET: /* choose correct colours for each part of the border line */ switch (light) { diff --git a/content/handlers/html/script.c b/content/handlers/html/script.c index 962386d68..554fc4f70 100644 --- a/content/handlers/html/script.c +++ b/content/handlers/html/script.c @@ -495,6 +495,7 @@ exec_src_script(html_content *c, switch (script_type) { case HTML_SCRIPT_SYNC: ret = DOM_HUBBUB_HUBBUB_ERR | HUBBUB_PAUSED; + break; case HTML_SCRIPT_ASYNC: break; diff --git a/content/handlers/html/table.c b/content/handlers/html/table.c index 4ffcceab9..f8762e862 100644 --- a/content/handlers/html/table.c +++ b/content/handlers/html/table.c @@ -26,6 +26,7 @@ #include <dom/dom.h> #include "utils/log.h" +#include "utils/utils.h" #include "utils/talloc.h" #include "css/utils.h" @@ -93,27 +94,27 @@ table_border_is_more_eyecatching(const css_unit_ctx *unit_len_ctx, /* 3b -- sort by style */ switch (a->style) { - case CSS_BORDER_STYLE_DOUBLE: impact++; /* Fall through */ - case CSS_BORDER_STYLE_SOLID: impact++; /* Fall through */ - case CSS_BORDER_STYLE_DASHED: impact++; /* Fall through */ - case CSS_BORDER_STYLE_DOTTED: impact++; /* Fall through */ - case CSS_BORDER_STYLE_RIDGE: impact++; /* Fall through */ - case CSS_BORDER_STYLE_OUTSET: impact++; /* Fall through */ - case CSS_BORDER_STYLE_GROOVE: impact++; /* Fall through */ - case CSS_BORDER_STYLE_INSET: impact++; /* Fall through */ + case CSS_BORDER_STYLE_DOUBLE: impact++; fallthrough; + case CSS_BORDER_STYLE_SOLID: impact++; fallthrough; + case CSS_BORDER_STYLE_DASHED: impact++; fallthrough; + case CSS_BORDER_STYLE_DOTTED: impact++; fallthrough; + case CSS_BORDER_STYLE_RIDGE: impact++; fallthrough; + case CSS_BORDER_STYLE_OUTSET: impact++; fallthrough; + case CSS_BORDER_STYLE_GROOVE: impact++; fallthrough; + case CSS_BORDER_STYLE_INSET: impact++; fallthrough; default: break; } switch (b->style) { - case CSS_BORDER_STYLE_DOUBLE: impact--; /* Fall through */ - case CSS_BORDER_STYLE_SOLID: impact--; /* Fall through */ - case CSS_BORDER_STYLE_DASHED: impact--; /* Fall through */ - case CSS_BORDER_STYLE_DOTTED: impact--; /* Fall through */ - case CSS_BORDER_STYLE_RIDGE: impact--; /* Fall through */ - case CSS_BORDER_STYLE_OUTSET: impact--; /* Fall through */ - case CSS_BORDER_STYLE_GROOVE: impact--; /* Fall through */ - case CSS_BORDER_STYLE_INSET: impact--; /* Fall through */ + case CSS_BORDER_STYLE_DOUBLE: impact--; fallthrough; + case CSS_BORDER_STYLE_SOLID: impact--; fallthrough; + case CSS_BORDER_STYLE_DASHED: impact--; fallthrough; + case CSS_BORDER_STYLE_DOTTED: impact--; fallthrough; + case CSS_BORDER_STYLE_RIDGE: impact--; fallthrough; + case CSS_BORDER_STYLE_OUTSET: impact--; fallthrough; + case CSS_BORDER_STYLE_GROOVE: impact--; fallthrough; + case CSS_BORDER_STYLE_INSET: impact--; fallthrough; default: break; } @@ -128,20 +129,20 @@ table_border_is_more_eyecatching(const css_unit_ctx *unit_len_ctx, /** \todo COL/COL_GROUP */ switch (a_src) { - case BOX_TABLE_CELL: impact++; /* Fall through */ - case BOX_TABLE_ROW: impact++; /* Fall through */ - case BOX_TABLE_ROW_GROUP: impact++; /* Fall through */ - case BOX_TABLE: impact++; /* Fall through */ + case BOX_TABLE_CELL: impact++; fallthrough; + case BOX_TABLE_ROW: impact++; fallthrough; + case BOX_TABLE_ROW_GROUP: impact++; fallthrough; + case BOX_TABLE: impact++; fallthrough; default: break; } /** \todo COL/COL_GROUP */ switch (b_src) { - case BOX_TABLE_CELL: impact--; /* Fall through */ - case BOX_TABLE_ROW: impact--; /* Fall through */ - case BOX_TABLE_ROW_GROUP: impact--; /* Fall through */ - case BOX_TABLE: impact--; /* Fall through */ + case BOX_TABLE_CELL: impact--; fallthrough; + case BOX_TABLE_ROW: impact--; fallthrough; + case BOX_TABLE_ROW_GROUP: impact--; fallthrough; + case BOX_TABLE: impact--; fallthrough; default: break; } diff --git a/content/handlers/image/Makefile b/content/handlers/image/Makefile index afc90f407..ac052b37a 100644 --- a/content/handlers/image/Makefile +++ b/content/handlers/image/Makefile @@ -7,6 +7,7 @@ S_IMAGE_$(NETSURF_USE_BMP) += bmp.c S_IMAGE_$(NETSURF_USE_GIF) += gif.c S_IMAGE_$(NETSURF_USE_BMP) += ico.c S_IMAGE_$(NETSURF_USE_JPEG) += jpeg.c +S_IMAGE_$(NETSURF_USE_JPEGXL) += jpegxl.c S_IMAGE_$(NETSURF_USE_ROSPRITE) += nssprite.c S_IMAGE_$(NETSURF_USE_PNG) += png.c S_IMAGE_$(NETSURF_USE_NSSVG) += svg.c diff --git a/content/handlers/image/image.c b/content/handlers/image/image.c index 3107ee495..2bd5f5f8d 100644 --- a/content/handlers/image/image.c +++ b/content/handlers/image/image.c @@ -32,6 +32,7 @@ #include "image/gif.h" #include "image/ico.h" #include "image/jpeg.h" +#include "image/jpegxl.h" #include "image/nssprite.h" #include "image/png.h" #include "image/rsvg.h" @@ -72,6 +73,12 @@ nserror image_init(void) return error; #endif +#ifdef WITH_JPEGXL + error = nsjpegxl_init(); + if (error != NSERROR_OK) + return error; +#endif + #ifdef WITH_PNG error = nspng_init(); if (error != NSERROR_OK) diff --git a/content/handlers/image/jpeg.c b/content/handlers/image/jpeg.c index e07fb47bb..93372f15a 100644 --- a/content/handlers/image/jpeg.c +++ b/content/handlers/image/jpeg.c @@ -206,7 +206,9 @@ static inline void nsjpeg__decode_rgb( uint8_t * volatile pixels, size_t rowstride) { +#if RGB_RED != 0 || RGB_GREEN != 1 || RGB_BLUE != 2 || RGB_PIXELSIZE != 4 int width = cinfo->output_width; +#endif do { JSAMPROW scanlines[1] = { diff --git a/content/handlers/image/jpegxl.c b/content/handlers/image/jpegxl.c new file mode 100644 index 000000000..01c704577 --- /dev/null +++ b/content/handlers/image/jpegxl.c @@ -0,0 +1,340 @@ +/* + * Copyright 2023 Vincent Sanders <vince@netsurf-browser.org> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** + * \file + * implementation of content handling for image/jpegxl + * + * This implementation uses the JXL library. + */ + +#include <stdbool.h> +#include <stdlib.h> +#include <setjmp.h> +#include <string.h> + +#include <jxl/decode.h> + +#include "utils/utils.h" +#include "utils/log.h" +#include "utils/messages.h" +#include "netsurf/bitmap.h" +#include "content/llcache.h" +#include "content/content.h" +#include "content/content_protected.h" +#include "content/content_factory.h" +#include "desktop/gui_internal.h" +#include "desktop/bitmap.h" + +#include "image/image_cache.h" + +#include "image/jpegxl.h" + + +/** + * output image format + */ +static const JxlPixelFormat jxl_output_format = { + .num_channels = 4, + .data_type = JXL_TYPE_UINT8, + .endianness = JXL_LITTLE_ENDIAN, + .align = 0, +}; + +/** + * Content create entry point. + */ +static nserror +nsjpegxl_create(const content_handler *handler, + lwc_string *imime_type, const struct http_parameter *params, + llcache_handle *llcache, const char *fallback_charset, + bool quirks, struct content **c) +{ + struct content *jpeg; + nserror error; + + jpeg = calloc(1, sizeof(struct content)); + if (jpeg == NULL) + return NSERROR_NOMEM; + + error = content__init(jpeg, handler, imime_type, params, + llcache, fallback_charset, quirks); + if (error != NSERROR_OK) { + free(jpeg); + return error; + } + + *c = jpeg; + + return NSERROR_OK; +} + +/** + * create a bitmap from jpeg xl content. + */ +static struct bitmap * +jpegxl_cache_convert(struct content *c) +{ + struct bitmap * bitmap = NULL; + JxlDecoder *jxldec; + JxlDecoderStatus decstatus; + JxlBasicInfo binfo; + const uint8_t *src_data; + size_t src_size; + uint8_t * output; + bitmap_fmt_t jxl_fmt = { + /** TODO: At the moment we have to set the layout to the only + * pixel layout that libjxl supports. It looks like they + * plan to add support for decoding to other layouts + * in the future, as shown by the TODO in the docs: + * + * https://libjxl.readthedocs.io/en/latest/api_common.html#_CPPv414JxlPixelFormat + */ + .layout = BITMAP_LAYOUT_R8G8B8A8, + .pma = bitmap_fmt.pma, + }; + + jxldec = JxlDecoderCreate(NULL); + if (jxldec == NULL) { + NSLOG(netsurf, ERROR, "Unable to allocate decoder"); + return NULL; + } + + decstatus = JxlDecoderSetUnpremultiplyAlpha(jxldec, !bitmap_fmt.pma); + if (decstatus != JXL_DEC_SUCCESS) { + NSLOG(netsurf, ERROR, "unable to set premultiplied alpha status: %d", + decstatus); + JxlDecoderDestroy(jxldec); + return NULL; + } + + decstatus= JxlDecoderSubscribeEvents(jxldec, JXL_DEC_FULL_IMAGE); + if (decstatus != JXL_DEC_SUCCESS) { + NSLOG(netsurf, ERROR, "Unable to subscribe"); + return NULL; + } + src_data = content__get_source_data(c, &src_size); + + decstatus = JxlDecoderSetInput(jxldec, src_data, src_size); + if (decstatus != JXL_DEC_SUCCESS) { + NSLOG(netsurf, ERROR, "unable to set input"); + return NULL; + } + + decstatus = JxlDecoderProcessInput(jxldec); + if (decstatus != JXL_DEC_NEED_IMAGE_OUT_BUFFER) { + NSLOG(netsurf, ERROR, + "expected status JXL_DEC_NEED_IMAGE_OUT_BUFFER(%d) got %d", + JXL_DEC_NEED_IMAGE_OUT_BUFFER, + decstatus); + JxlDecoderDestroy(jxldec); + return NULL; + } + + decstatus = JxlDecoderGetBasicInfo(jxldec, &binfo); + if (decstatus != JXL_DEC_SUCCESS) { + NSLOG(netsurf, ERROR, "unable to get basic info status:%d",decstatus); + JxlDecoderDestroy(jxldec); + return NULL; + } + + /* create bitmap with appropriate opacity */ + if (binfo.alpha_bits > 0) { + bitmap = guit->bitmap->create(c->width, c->height, BITMAP_OPAQUE); + } else { + bitmap = guit->bitmap->create(c->width, c->height, BITMAP_NONE); + } + if (bitmap == NULL) { + /* empty bitmap could not be created */ + JxlDecoderDestroy(jxldec); + return NULL; + } + + /* ensure buffer was allocated */ + output = guit->bitmap->get_buffer(bitmap); + if (output == NULL) { + /* bitmap with no buffer available */ + guit->bitmap->destroy(bitmap); + JxlDecoderDestroy(jxldec); + return NULL; + } + decstatus = JxlDecoderSetImageOutBuffer(jxldec, &jxl_output_format, output, c->size); + if (decstatus != JXL_DEC_SUCCESS) { + NSLOG(netsurf, ERROR, "unable to set output buffer callback status:%d",decstatus); + guit->bitmap->destroy(bitmap); + JxlDecoderDestroy(jxldec); + return NULL; + } + + decstatus = JxlDecoderProcessInput(jxldec); + if (decstatus != JXL_DEC_FULL_IMAGE) { + NSLOG(netsurf, ERROR, "did not get decode event"); + guit->bitmap->destroy(bitmap); + JxlDecoderDestroy(jxldec); + return NULL; + } + + JxlDecoderDestroy(jxldec); + + bitmap_format_to_client(bitmap, &jxl_fmt); + guit->bitmap->modified(bitmap); + + return bitmap; +} + +/** + * report failiure + */ +static bool jxl_report_fail(struct content *c, JxlDecoderStatus decstatus, const char *msg) +{ + union content_msg_data msg_data; + NSLOG(netsurf, ERROR, "%s decoder status:%d", msg, decstatus); + msg_data.errordata.errorcode = NSERROR_UNKNOWN; + msg_data.errordata.errormsg = msg; + content_broadcast(c, CONTENT_MSG_ERROR, &msg_data); + return false; +} + +/** + * Convert a CONTENT_JPEGXL for display. + */ +static bool nsjpegxl_convert(struct content *c) +{ + JxlDecoder *jxldec; + JxlSignature decsig; + JxlDecoderStatus decstatus = JXL_DEC_ERROR; + JxlBasicInfo binfo; + union content_msg_data msg_data; + const uint8_t *data; + size_t size; + char *title; + size_t image_size; + + /* check image header is valid and get width/height */ + data = content__get_source_data(c, &size); + + decsig = JxlSignatureCheck(data,size); + if ((decsig != JXL_SIG_CODESTREAM) && (decsig != JXL_SIG_CONTAINER)) { + NSLOG(netsurf, ERROR, "signature failed"); + msg_data.errordata.errorcode = NSERROR_UNKNOWN; + msg_data.errordata.errormsg = "Signature failed"; + content_broadcast(c, CONTENT_MSG_ERROR, &msg_data); + return false; + } + + jxldec = JxlDecoderCreate(NULL); + if (jxldec == NULL) { + return jxl_report_fail(c, decstatus, "Unable to allocate decoder"); + } + decstatus= JxlDecoderSubscribeEvents(jxldec, JXL_DEC_BASIC_INFO); + if (decstatus != JXL_DEC_SUCCESS) { + return jxl_report_fail(c, decstatus, "Unable to subscribe"); + } + decstatus = JxlDecoderSetInput(jxldec, data,size); + if (decstatus != JXL_DEC_SUCCESS) { + return jxl_report_fail(c, decstatus, "unable to set input"); + } + decstatus = JxlDecoderProcessInput(jxldec); + if (decstatus != JXL_DEC_BASIC_INFO) { + return jxl_report_fail(c, decstatus, "did not get basic info event"); + } + decstatus = JxlDecoderGetBasicInfo(jxldec, &binfo); + if (decstatus != JXL_DEC_SUCCESS) { + return jxl_report_fail(c, decstatus, "unable to get basic info"); + } + decstatus = JxlDecoderImageOutBufferSize(jxldec, &jxl_output_format, &image_size); + if (decstatus != JXL_DEC_SUCCESS) { + return jxl_report_fail(c, decstatus, "unable get image size"); + } + + JxlDecoderDestroy(jxldec); + + NSLOG(netsurf, INFO, "got basic info size:%ld x:%d y:%d", image_size, binfo.xsize, binfo.ysize); + + c->width = binfo.xsize; + c->height = binfo.ysize; + c->size = image_size; + + image_cache_add(c, NULL, jpegxl_cache_convert); + + /* set title text */ + title = messages_get_buff("JPEGXLTitle", + nsurl_access_leaf(llcache_handle_get_url(c->llcache)), + c->width, c->height); + if (title != NULL) { + content__set_title(c, title); + free(title); + } + + content_set_ready(c); + content_set_done(c); + content_set_status(c, ""); /* Done: update status bar */ + + return true; +} + + +/** + * Clone content. + */ +static nserror nsjpegxl_clone(const struct content *old, struct content **newc) +{ + struct content *jpegxl_c; + nserror error; + + jpegxl_c = calloc(1, sizeof(struct content)); + if (jpegxl_c == NULL) + return NSERROR_NOMEM; + + error = content__clone(old, jpegxl_c); + if (error != NSERROR_OK) { + content_destroy(jpegxl_c); + return error; + } + + /* re-convert if the content is ready */ + if ((old->status == CONTENT_STATUS_READY) || + (old->status == CONTENT_STATUS_DONE)) { + if (nsjpegxl_convert(jpegxl_c) == false) { + content_destroy(jpegxl_c); + return NSERROR_CLONE_FAILED; + } + } + + *newc = jpegxl_c; + + return NSERROR_OK; +} + +static const content_handler nsjpegxl_content_handler = { + .create = nsjpegxl_create, + .data_complete = nsjpegxl_convert, + .destroy = image_cache_destroy, + .redraw = image_cache_redraw, + .clone = nsjpegxl_clone, + .get_internal = image_cache_get_internal, + .type = image_cache_content_type, + .is_opaque = image_cache_is_opaque, + .no_share = false, +}; + +static const char *nsjpegxl_types[] = { + "image/jxl", +}; + +CONTENT_FACTORY_REGISTER_TYPES(nsjpegxl, nsjpegxl_types, nsjpegxl_content_handler); diff --git a/content/handlers/image/jpegxl.h b/content/handlers/image/jpegxl.h new file mode 100644 index 000000000..e37d9344e --- /dev/null +++ b/content/handlers/image/jpegxl.h @@ -0,0 +1,28 @@ +/* + * Copyright 2023 Vincent Sanders <vince@netsurf-browser.org> + * + * This file is part of NetSurf, http://www.netsurf-browser.org/ + * + * NetSurf is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; version 2 of the License. + * + * NetSurf is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <http://www.gnu.org/licenses/>. + */ + +/** \file + * Content for image/jpegxl (interface). + */ + +#ifndef _NETSURF_IMAGE_JPEGXL_H_ +#define _NETSURF_IMAGE_JPEGXL_H_ + +nserror nsjpegxl_init(void); + +#endif diff --git a/content/handlers/image/nssprite.c b/content/handlers/image/nssprite.c index a98c48aa2..c18f49063 100644 --- a/content/handlers/image/nssprite.c +++ b/content/handlers/image/nssprite.c @@ -124,7 +124,7 @@ static bool nssprite_convert(struct content *c) content_broadcast_error(c, NSERROR_NOMEM, NULL); return false; } - uint32_t* imagebuf = (uint32_t *)guit->bitmap->get_buffer(nssprite->bitmap); + uint32_t* imagebuf = (uint32_t *)(void *)guit->bitmap->get_buffer(nssprite->bitmap); if (!imagebuf) { content_broadcast_error(c, NSERROR_NOMEM, NULL); return false; diff --git a/content/handlers/image/webp.c b/content/handlers/image/webp.c index da13316bc..c04c0efd2 100644 --- a/content/handlers/image/webp.c +++ b/content/handlers/image/webp.c @@ -142,7 +142,7 @@ webp_cache_convert(struct content *c) default: /* WebP has no ABGR function, fall back to default. */ webp_fmt.layout = BITMAP_LAYOUT_R8G8B8A8; - /* Fall through. */ + fallthrough; case BITMAP_LAYOUT_R8G8B8A8: decoded = WebPDecodeRGBAInto(source_data, source_size, pixels, rowstride * webpfeatures.height, rowstride); diff --git a/content/handlers/javascript/duktape/dukky.c b/content/handlers/javascript/duktape/dukky.c index 52a9c82cf..a780b0067 100644 --- a/content/handlers/javascript/duktape/dukky.c +++ b/content/handlers/javascript/duktape/dukky.c @@ -385,7 +385,7 @@ static void dukky_html_element_class_from_tag_type(dom_html_element_type type, break; case DOM_HTML_ELEMENT_TYPE__COUNT: assert(type != DOM_HTML_ELEMENT_TYPE__COUNT); - /* fallthrough */ + fallthrough; case DOM_HTML_ELEMENT_TYPE__UNKNOWN: SET_HTML_CLASS(UNKNOWN) break; @@ -1156,7 +1156,7 @@ static void dukky_generic_event_handler(dom_event *evt, void *pw) NSLOG(dukky, DEBUG, "Unable to find the event name"); return; } - NSLOG(dukky, DEBUG, "Event's name is %*s", dom_string_length(name), + NSLOG(dukky, DEBUG, "Event's name is %*s", (int)dom_string_length(name), dom_string_data(name)); exc = dom_event_get_event_phase(evt, &phase); if (exc != DOM_NO_ERR) { @@ -1394,10 +1394,10 @@ void dukky_register_event_listener_for(duk_context *ctx, if (exc != DOM_NO_ERR) { NSLOG(dukky, DEBUG, "Unable to register listener for %p.%*s", ele, - dom_string_length(name), dom_string_data(name)); + (int)dom_string_length(name), dom_string_data(name)); } else { NSLOG(dukky, DEBUG, "have registered listener for %p.%*s", - ele, dom_string_length(name), dom_string_data(name)); + ele, (int)dom_string_length(name), dom_string_data(name)); } dom_event_listener_unref(listen); } diff --git a/content/handlers/text/textplain.c b/content/handlers/text/textplain.c index 60051f5c9..cee89a1a5 100644 --- a/content/handlers/text/textplain.c +++ b/content/handlers/text/textplain.c @@ -264,7 +264,7 @@ textplain_drain_input(textplain_content *c, parserutils_inputstream *stream, parserutils_error terminator) { - static const uint8_t *u_fffd = (const uint8_t *) "\xef\xbf\xfd"; + static const uint8_t *u_fffd = (const uint8_t *) "\xef\xbf\xbd"; const uint8_t *ch; size_t chlen, offset = 0; diff --git a/content/hlcache.c b/content/hlcache.c index d860015a5..5cba88bc6 100644 --- a/content/hlcache.c +++ b/content/hlcache.c @@ -30,6 +30,7 @@ #include "utils/messages.h" #include "utils/ring.h" #include "utils/utils.h" +#include "netsurf/inttypes.h" #include "netsurf/misc.h" #include "netsurf/content.h" #include "desktop/gui_internal.h" @@ -592,7 +593,7 @@ void hlcache_finalise(void) num_contents++; } - NSLOG(netsurf, INFO, "%d contents remain before cache drain", + NSLOG(netsurf, INFO, "%"PRIu32" contents remain before cache drain", num_contents); /* Drain cache */ @@ -607,7 +608,8 @@ void hlcache_finalise(void) } } while (num_contents > 0 && num_contents != prev_contents); - NSLOG(netsurf, INFO, "%d contents remaining after being polite", num_contents); + NSLOG(netsurf, INFO, "%"PRIu32" contents remaining after being polite", + num_contents); /* Drain cache again, forcing the matter */ do { @@ -621,12 +623,12 @@ void hlcache_finalise(void) } } while (num_contents > 0 && num_contents != prev_contents); - NSLOG(netsurf, INFO, "%d contents remaining:", num_contents); + NSLOG(netsurf, INFO, "%"PRIu32" contents remaining:", num_contents); for (entry = hlcache->content_list; entry != NULL; entry = entry->next) { hlcache_handle entry_handle = { entry, NULL, NULL }; if (entry->content != NULL) { - NSLOG(netsurf, INFO, " %p : %s (%d users)", + NSLOG(netsurf, INFO, " %p : %s (%"PRIu32" users)", entry, nsurl_access(hlcache_handle_get_url(&entry_handle)), content_count_users(entry->content)); diff --git a/content/llcache.c b/content/llcache.c index f86ae0d42..32c7449d2 100644 --- a/content/llcache.c +++ b/content/llcache.c @@ -1923,7 +1923,7 @@ llcache_object_retrieve_from_cache(nsurl *url, llcache_object *obj, *newest = NULL; NSLOG(llcache, DEBUG, - "Searching cache for %s flags:%x referer:%s post:%p", + "Searching cache for %s flags:%"PRIx32" referer:%s post:%p", nsurl_access(url), flags, referer==NULL?"":nsurl_access(referer), post); @@ -2100,7 +2100,7 @@ llcache_object_retrieve(nsurl *url, nsurl *defragmented_url; bool uncachable = false; - NSLOG(llcache, DEBUG, "Retrieve %s (%x, %s, %p)", nsurl_access(url), flags, + NSLOG(llcache, DEBUG, "Retrieve %s (%"PRIx32", %s, %p)", nsurl_access(url), flags, referer==NULL?"":nsurl_access(referer), post); @@ -2207,10 +2207,17 @@ static nserror llcache_hsts_transform_url(nsurl *url, nsurl **result, scheme = nsurl_get_component(url, NSURL_SCHEME); if (lwc_string_caseless_isequal(scheme, corestring_lwc_http, &match) != lwc_error_ok || match == false) { - /* Non-HTTP fetch: ignore */ + /* Non-HTTP fetch: no transform required */ + if (lwc_string_caseless_isequal(scheme, corestring_lwc_https, + &match) == lwc_error_ok && match) { + /* HTTPS: ask urldb if HSTS is enabled */ + *hsts_in_use = urldb_get_hsts_enabled(url); + } else { + /* Anything else: no HSTS */ + *hsts_in_use = false; + } lwc_string_unref(scheme); *result = nsurl_ref(url); - *hsts_in_use = false; return error; } lwc_string_unref(scheme); @@ -3876,7 +3883,7 @@ void llcache_clean(bool purge) } } - NSLOG(llcache, DEBUG, "Size: %u (limit: %u)", llcache_size, limit); + NSLOG(llcache, DEBUG, "Size: %"PRIu32" (limit: %"PRIu32")", llcache_size, limit); } /* Exported interface documented in content/llcache.h */ @@ -3897,7 +3904,7 @@ llcache_initialise(const struct llcache_parameters *prm) llcache->all_caught_up = true; NSLOG(llcache, INFO, - "llcache initialising with a limit of %d bytes", + "llcache initialising with a limit of %"PRIu32" bytes", llcache->limit); /* backing store initialisation */ diff --git a/content/mimesniff.c b/content/mimesniff.c index 9a11834f9..adc000dd7 100644 --- a/content/mimesniff.c +++ b/content/mimesniff.c @@ -260,6 +260,13 @@ static nserror mimesniff__match_unknown_exact(const uint8_t *data, size_t len, SIG(&corestring_lwc_application_x_gzip, "\x1f\x8b\x08", true), SIG(&corestring_lwc_application_postscript, "%!PS-Adobe-",true), SIG(&corestring_lwc_application_pdf, "%PDF-", false), + SIG(&corestring_lwc_image_jxl, "\xFF\x0A", true), /* containerless jpeg xl*/ + { + (const uint8_t *)"\x00\x00\x00\x0CJXL \x0D\x0A\x87\x0A", + 12, + true, + &corestring_lwc_image_jxl + }, /* containered jpeg xl*/ { NULL, 0, false, NULL } }; #undef SIG @@ -376,6 +383,12 @@ static nserror mimesniff__compute_image(lwc_string *official_type, SIG(&corestring_lwc_image_jpeg, "\xff\xd8\xff"), SIG(&corestring_lwc_image_bmp, "BM"), SIG(&corestring_lwc_image_vnd_microsoft_icon, "\x00\x00\x01\x00"), + SIG(&corestring_lwc_image_jxl, "\xFF\x0A"), /* containerless jpeg xl*/ + { + (const uint8_t *)"\x00\x00\x00\x0CJXL \x0D\x0A\x87\x0A", + 12, + &corestring_lwc_image_jxl + }, /* containered jpeg xl*/ { NULL, 0, NULL } }; #undef SIG diff --git a/content/urldb.c b/content/urldb.c index 7352d67c3..881f76f6d 100644 --- a/content/urldb.c +++ b/content/urldb.c @@ -115,11 +115,6 @@ #include "content/content.h" #include "content/urldb.h" -#ifdef WITH_AMISSL -/* AmiSSL needs everything to be using bsdsocket directly to avoid conflicts */ -#include <proto/bsdsocket.h> -#endif - /** * cookie entry. * |