From c9ead9bd1cdc7fa03d5e9eb20ebed37e27110407 Mon Sep 17 00:00:00 2001 From: Stefan Eissing Date: Mon, 27 Jul 2026 09:49:33 +0200 Subject: [PATCH 01/15] conncache: conn upkeep/alive: move and enhance - move `Curl_conn_seems_dead()` into conncache.c - move `Curl_conn_upkeep()` into conncache.c - when upkeep gives an error on a connection not in use, terminate it Closes #21806 --- lib/cfilters.c | 22 +++++----- lib/cfilters.h | 5 +-- lib/conncache.c | 99 ++++++++++++++++++++++++++++++++++++++++-- lib/conncache.h | 7 +++ lib/url.c | 113 ++---------------------------------------------- lib/url.h | 19 +------- 6 files changed, 122 insertions(+), 143 deletions(-) diff --git a/lib/cfilters.c b/lib/cfilters.c index bef39e6f5b..0af8c4bede 100644 --- a/lib/cfilters.c +++ b/lib/cfilters.c @@ -450,9 +450,9 @@ static CURLcode cf_cntrl_all(struct connectdata *conn, int event, int arg1, void *arg2) { CURLcode result = CURLE_OK; - size_t i; + int i; - for(i = 0; i < CURL_ARRAYSIZE(conn->cfilter); ++i) { + for(i = 0; i < (int)CURL_ARRAYSIZE(conn->cfilter); ++i) { result = Curl_conn_cf_cntrl(conn->cfilter[i], data, ignore_result, event, arg1, arg2); if(!ignore_result && result) @@ -753,7 +753,7 @@ CURLcode Curl_conn_adjust_pollset(struct Curl_easy *data, * connect or shutdown does not add poll events for the other. Check * against the transfer's own interest, before any chain added sockets * of its own. */ - for(i = 0; (i < 2) && !result; ++i) { + for(i = 0; (i < (int)CURL_ARRAYSIZE(conn->cfilter)) && !result; ++i) { if(conn->cfilter[i] && (want_io || !Curl_conn_is_connected(conn, i) || Curl_shutdown_started(conn, i))) @@ -978,15 +978,17 @@ bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn, } CURLcode Curl_conn_keep_alive(struct Curl_easy *data, - struct connectdata *conn, - int sockindex) + struct connectdata *conn) { - struct Curl_cfilter *cf; + CURLcode result = CURLE_OK; + int i; - if(!CONN_SOCK_IDX_VALID(sockindex)) - return CURLE_BAD_FUNCTION_ARGUMENT; - cf = conn->cfilter[sockindex]; - return cf ? cf->cft->keep_alive(cf, data) : CURLE_OK; + for(i = 0; (i < (int)CURL_ARRAYSIZE(conn->cfilter)) && !result; ++i) { + struct Curl_cfilter *cf = conn->cfilter[i]; + if(cf) + result = cf->cft->keep_alive(cf, data); + } + return result; } size_t Curl_conn_get_max_concurrent(struct Curl_easy *data, diff --git a/lib/cfilters.h b/lib/cfilters.h index f55a572e2e..cfdb5782ee 100644 --- a/lib/cfilters.h +++ b/lib/cfilters.h @@ -558,11 +558,10 @@ bool Curl_conn_is_alive(struct Curl_easy *data, struct connectdata *conn, bool *input_pending); /** - * Try to upkeep the connection filters at sockindex. + * Try to upkeep the connection filters. */ CURLcode Curl_conn_keep_alive(struct Curl_easy *data, - struct connectdata *conn, - int sockindex); + struct connectdata *conn); /** * Get the remote hostname and port that the connection is currently diff --git a/lib/conncache.c b/lib/conncache.c index eb88d67dc8..897b41cc42 100644 --- a/lib/conncache.c +++ b/lib/conncache.c @@ -715,7 +715,7 @@ static int cpool_reap_dead_cb(struct Curl_easy *data, if(!terminate) { reaper->checked++; - terminate = Curl_conn_seems_dead(conn, data, &reaper->now); + terminate = Curl_cpool_conn_seems_dead(conn, data, &reaper->now); } if(terminate) { /* stop the iteration here, pass back the connection that was pruned */ @@ -761,7 +761,21 @@ static int conn_upkeep(struct Curl_easy *data, void *param) { (void)param; - Curl_conn_upkeep(data, conn); + if(curlx_ptimediff_ms(Curl_pgrs_now(data), &conn->keepalive) >= + data->set.upkeep_interval_ms) { + CURLcode result; + + /* briefly attach for action */ + Curl_attach_connection(data, conn); + result = Curl_conn_keep_alive(data, conn); + conn->keepalive = *Curl_pgrs_now(data); + Curl_detach_connection(data); + + if(result && !CONN_INUSE(conn)) { + Curl_conn_terminate(data, conn, FALSE); + return 1; + } + } return 0; /* continue iteration */ } @@ -773,7 +787,8 @@ CURLcode Curl_cpool_upkeep(struct Curl_easy *data) return CURLE_OK; CPOOL_LOCK(cpool, data); - cpool_foreach(data, cpool, NULL, conn_upkeep); + while(cpool_foreach(data, cpool, NULL, conn_upkeep)) + ; CPOOL_UNLOCK(cpool, data); return CURLE_OK; } @@ -858,6 +873,84 @@ void Curl_cpool_nw_changed(struct Curl_easy *data) } } +/* A connection has to have been idle for less than 'conn_max_idle_ms' + (the success rate is too low after this), or created less than + 'conn_max_age_ms' ago, to be subject for reuse. */ +static bool cpool_conn_maxage(struct Curl_easy *data, + struct connectdata *conn, + const struct curltime *pnow) +{ + timediff_t age_ms; + + if(data->set.conn_max_idle_ms) { + age_ms = curlx_ptimediff_ms(pnow, &conn->lastused); + if(age_ms > data->set.conn_max_idle_ms) { + infof(data, "Too old connection (%" FMT_TIMEDIFF_T + " ms idle, max idle is %" FMT_TIMEDIFF_T " ms), disconnect it", + age_ms, data->set.conn_max_idle_ms); + return TRUE; + } + } + + if(data->set.conn_max_age_ms) { + age_ms = curlx_ptimediff_ms(pnow, &conn->created); + if(age_ms > data->set.conn_max_age_ms) { + infof(data, + "Too old connection (created %" FMT_TIMEDIFF_T + " ms ago, max lifetime is %" FMT_TIMEDIFF_T " ms), disconnect it", + age_ms, data->set.conn_max_age_ms); + return TRUE; + } + } + + return FALSE; +} + +/* + * Return TRUE iff the given connection is considered dead. + */ +bool Curl_cpool_conn_seems_dead(struct connectdata *conn, + struct Curl_easy *data, + const struct curltime *pnow) +{ + bool input_pending = FALSE; + bool dead = FALSE; + + DEBUGASSERT(!data->conn); + /* The check only makes sense only if the connection is not in use */ + if(CONN_INUSE(conn)) + return FALSE; + else if(cpool_conn_maxage(data, conn, pnow)) /* too old? */ + return TRUE; + else if(curlx_ptimediff_ms(pnow, &conn->lastchecked) < 1000) + return FALSE; + else if(conn->scheme->run->connection_is_dead) { + Curl_attach_connection(data, conn); + dead = conn->scheme->run->connection_is_dead(data, conn); + Curl_detach_connection(data); + } + else { + Curl_attach_connection(data, conn); + dead = !Curl_conn_is_alive(data, conn, &input_pending); + Curl_detach_connection(data); + } + + if(input_pending) { + /* For reuse, we want a "clean" connection state. This includes + * that we expect - in general - no waiting input data. Input + * waiting might be a TLS Notify Close, for example. We reject + * that. + * For protocols where data from other end may arrive at + * any time (HTTP/2 PING for example), the protocol handler needs + * to install its own `connection_check` callback. + */ + DEBUGF(infof(data, "connection has input pending, not reusable")); + dead = TRUE; + } + + return dead; +} + #if 0 /* Useful for debugging the connection pool */ void Curl_cpool_print(struct cpool *cpool) diff --git a/lib/conncache.h b/lib/conncache.h index 78ccd8282f..6798a3b8b3 100644 --- a/lib/conncache.h +++ b/lib/conncache.h @@ -156,4 +156,11 @@ void Curl_cpool_do_locked(struct Curl_easy *data, /* Close all unused connections, prevent reuse of existing ones. */ void Curl_cpool_nw_changed(struct Curl_easy *data); +/** + * Return TRUE iff the given connection is considered dead. + */ +bool Curl_cpool_conn_seems_dead(struct connectdata *conn, + struct Curl_easy *data, + const struct curltime *pnow); + #endif /* HEADER_CURL_CONNCACHE_H */ diff --git a/lib/url.c b/lib/url.c index 1c837c586e..4cb2535033 100644 --- a/lib/url.c +++ b/lib/url.c @@ -564,115 +564,6 @@ static bool proxy_info_matches(const struct proxy_info *data, } #endif -/* A connection has to have been idle for less than 'conn_max_idle_ms' - (the success rate is too low after this), or created less than - 'conn_max_age_ms' ago, to be subject for reuse. */ -static bool conn_maxage(struct Curl_easy *data, - struct connectdata *conn, - struct curltime now) -{ - timediff_t age_ms; - - if(data->set.conn_max_idle_ms) { - age_ms = curlx_ptimediff_ms(&now, &conn->lastused); - if(age_ms > data->set.conn_max_idle_ms) { - infof(data, "Too old connection (%" FMT_TIMEDIFF_T - " ms idle, max idle is %" FMT_TIMEDIFF_T " ms), disconnect it", - age_ms, data->set.conn_max_idle_ms); - return TRUE; - } - } - - if(data->set.conn_max_age_ms) { - age_ms = curlx_ptimediff_ms(&now, &conn->created); - if(age_ms > data->set.conn_max_age_ms) { - infof(data, - "Too old connection (created %" FMT_TIMEDIFF_T - " ms ago, max lifetime is %" FMT_TIMEDIFF_T " ms), disconnect it", - age_ms, data->set.conn_max_age_ms); - return TRUE; - } - } - - return FALSE; -} - -/* - * Return TRUE iff the given connection is considered dead. - */ -bool Curl_conn_seems_dead(struct connectdata *conn, - struct Curl_easy *data, - const struct curltime *pnow) -{ - DEBUGASSERT(!data->conn); - if(!CONN_INUSE(conn)) { - /* The check for a dead socket makes sense only if the connection is not in - use */ - bool dead; - - if(conn_maxage(data, conn, *pnow)) { - /* avoid check if already too old */ - dead = TRUE; - } - else if(curlx_ptimediff_ms(pnow, &conn->lastchecked) < 1000) - dead = FALSE; - else if(conn->scheme->run->connection_is_dead) { - /* The protocol has a special method for checking the state of the - connection. Use it to check if the connection is dead. */ - /* briefly attach the connection for the check */ - Curl_attach_connection(data, conn); - dead = conn->scheme->run->connection_is_dead(data, conn); - Curl_detach_connection(data); - conn->lastchecked = *pnow; - } - else { - bool input_pending = FALSE; - - Curl_attach_connection(data, conn); - dead = !Curl_conn_is_alive(data, conn, &input_pending); - if(input_pending) { - /* For reuse, we want a "clean" connection state. This includes - * that we expect - in general - no waiting input data. Input - * waiting might be a TLS Notify Close, for example. We reject - * that. - * For protocols where data from other end may arrive at - * any time (HTTP/2 PING for example), the protocol handler needs - * to install its own `connection_check` callback. - */ - DEBUGF(infof(data, "connection has input pending, not reusable")); - dead = TRUE; - } - Curl_detach_connection(data); - conn->lastchecked = *pnow; - } - - if(dead) { - /* remove connection from cpool */ - infof(data, "Connection %" FMT_OFF_T " seems to be dead", - conn->connection_id); - return TRUE; - } - } - return FALSE; -} - -CURLcode Curl_conn_upkeep(struct Curl_easy *data, - struct connectdata *conn) -{ - CURLcode result = CURLE_OK; - if(curlx_ptimediff_ms(Curl_pgrs_now(data), &conn->keepalive) <= - data->set.upkeep_interval_ms) - return result; - - /* briefly attach for action */ - Curl_attach_connection(data, conn); - result = Curl_conn_keep_alive(data, conn, FIRSTSOCKET); - Curl_detach_connection(data); - - conn->keepalive = *Curl_pgrs_now(data); - return result; -} - #ifdef USE_SSH static bool ssh_config_matches(struct connectdata *one, struct connectdata *two) @@ -1172,8 +1063,10 @@ static bool url_match_conn(struct connectdata *conn, void *userdata) if(!url_match_multiplex_limits(conn, m)) return FALSE; - if(!CONN_INUSE(conn) && Curl_conn_seems_dead(conn, m->data, &m->now)) { + if(Curl_cpool_conn_seems_dead(conn, m->data, &m->now)) { /* remove and disconnect. */ + infof(m->data, "Connection %" FMT_OFF_T " seems to be dead, terminating", + conn->connection_id); Curl_conn_terminate(m->data, conn, FALSE); return FALSE; } diff --git a/lib/url.h b/lib/url.h index 02f1bd3943..c1df2fe811 100644 --- a/lib/url.h +++ b/lib/url.h @@ -71,23 +71,8 @@ void *Curl_conn_meta_get(struct connectdata *conn, const char *key); #define CURL_DEFAULT_HTTPS_PROXY_PORT 443 /* default https proxy port unless specified */ -/** - * Return TRUE iff the given connection is considered dead. - */ -bool Curl_conn_seems_dead(struct connectdata *conn, - struct Curl_easy *data, - const struct curltime *pnow); - -/** - * Perform upkeep operations on the connection. - */ -CURLcode Curl_conn_upkeep(struct Curl_easy *data, - struct connectdata *conn); - -/** - * Always eval all arguments, return the first - * result != (CURLE_OK | CURLE_AGAIN) or `r1`. - */ +/* Always eval all arguments, return the first + * result != (CURLE_OK | CURLE_AGAIN) or `r1`. */ CURLcode Curl_1st_fatal(CURLcode r1, CURLcode r2); #if defined(USE_HTTP2) || defined(USE_HTTP3) From a8881e5e1d2e22d4b085d45ab6c8ce1df251d602 Mon Sep 17 00:00:00 2001 From: Matthew John Cheetham Date: Mon, 13 Apr 2026 12:58:52 +0100 Subject: [PATCH 02/15] spnego: block NTLM fallback in SPNEGO negotiation - Switch the Windows SSPI identity struct to SEC_WINNT_AUTH_IDENTITY_EX to use !ntlm in PackageList to prevent NTLM from being offered. - For GSS filter out NTLMSSP OID, and restrict via gss_set_neg_mechs() to prevent NTLM from being offered. - Extend the GSS-API debug stub layer to support the NTLM blocking logic without a real Kerberos environment. - Update test 2057 to check that negotiate auth is silently skipped with no Authorization header when only NTLM stub credentials are available. - Add SPNEGO NTLM blocking test 2093 which verifies that Kerberos credentials still succeed when NTLM is blocked within SPNEGO. - Suppress tests valgrind leak for MIT krb5 gss_display_status, since the leak is in the library and not in curl. To suppress the tests valgrind leak, the wildcard '...' bridges over an anonymous frame inside libgssapi_krb5.so that valgrind reports as '???'. Signed-off-by: Matthew John Cheetham Aided-by: Johannes Schindelin Closes https://github.com/curl/curl/pull/21315 Closes https://github.com/curl/curl/pull/22410 --- CMakeLists.txt | 5 + configure.ac | 1 + docs/INSTALL-CMAKE.md | 1 + lib/curl_config-cmake.h.in | 3 + lib/curl_gssapi.c | 267 ++++++++++++++++++++++++++++++++++++- lib/curl_gssapi.h | 28 +++- lib/curl_sspi.c | 6 +- lib/curl_sspi.h | 6 +- lib/ldap.c | 2 +- lib/socks_gssapi.c | 3 +- lib/vauth/digest_sspi.c | 10 +- lib/vauth/krb5_gssapi.c | 3 +- lib/vauth/spnego_gssapi.c | 83 +++++++++++- lib/vauth/spnego_sspi.c | 26 ++++ lib/vauth/vauth.h | 13 +- tests/data/Makefile.am | 2 +- tests/data/test2057 | 55 ++------ tests/data/test2094 | 68 ++++++++++ tests/valgrind.supp | 11 ++ 19 files changed, 524 insertions(+), 69 deletions(-) create mode 100644 tests/data/test2094 diff --git a/CMakeLists.txt b/CMakeLists.txt index 663ca54081..dcb735d0ce 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1344,6 +1344,11 @@ if(CURL_USE_GSSAPI) elseif(GSS_VERSION) # MIT set(CURL_KRB5_VERSION "\"${GSS_VERSION}\"") endif() + + cmake_push_check_state() + list(APPEND CMAKE_REQUIRED_LIBRARIES CURL::gss) + check_function_exists("gss_set_neg_mechs" HAVE_GSS_SET_NEG_MECHS) + cmake_pop_check_state() else() message(WARNING "GSSAPI has been requested, but no supporting libraries found. Skipping.") endif() diff --git a/configure.ac b/configure.ac index 0d2ee2b3ff..c40bfb2a1c 100644 --- a/configure.ac +++ b/configure.ac @@ -2097,6 +2097,7 @@ if test "$want_gss" = "yes"; then AC_MSG_RESULT([no]) AC_MSG_ERROR([--with-gssapi was specified, but a GSS-API library was not found.]) ]) + AC_CHECK_FUNCS([gss_set_neg_mechs]) fi build_libstubgss=no diff --git a/docs/INSTALL-CMAKE.md b/docs/INSTALL-CMAKE.md index d241efb007..f5af80a418 100644 --- a/docs/INSTALL-CMAKE.md +++ b/docs/INSTALL-CMAKE.md @@ -517,6 +517,7 @@ the parent project, ideally in the "extra" find package redirect file: Available variables: - `HAVE_DES_ECB_ENCRYPT`: `DES_ecb_encrypt` present in OpenSSL (or fork). +- `HAVE_GSS_SET_NEG_MECHS`: `gss_set_neg_mechs` present in GSS-API library. - `HAVE_LDAP_INIT_FD`: `ldap_init_fd` present in LDAP library. - `HAVE_LDAP_URL_PARSE`: `ldap_url_parse` present in LDAP library. - `HAVE_MBEDTLS_DES_CRYPT_ECB`: `mbedtls_des_crypt_ecb` present in mbedTLS <4. diff --git a/lib/curl_config-cmake.h.in b/lib/curl_config-cmake.h.in index ffcce8273c..c992434530 100644 --- a/lib/curl_config-cmake.h.in +++ b/lib/curl_config-cmake.h.in @@ -330,6 +330,9 @@ /* if you have the GNU gssapi libraries */ #cmakedefine HAVE_GSSGNU 1 +/* if you have gss_set_neg_mechs */ +#cmakedefine HAVE_GSS_SET_NEG_MECHS 1 + /* MIT Kerberos version */ #cmakedefine CURL_KRB5_VERSION ${CURL_KRB5_VERSION} diff --git a/lib/curl_gssapi.c b/lib/curl_gssapi.c index fbc3c262f1..ccc24e09b1 100644 --- a/lib/curl_gssapi.c +++ b/lib/curl_gssapi.c @@ -81,7 +81,6 @@ enum min_err_code { /* libcurl is also passing this struct to these functions, which are not yet * stubbed: - * gss_inquire_context() * gss_unwrap() * gss_wrap() */ @@ -93,6 +92,12 @@ struct stub_gss_ctx_id_t_desc { char creds[250]; }; +/* Stub credential: tracks which mechanisms are allowed */ +struct stub_gss_cred_id_t_desc { + int allow_krb5; + int allow_ntlm; +}; + static OM_uint32 stub_gss_init_sec_context( OM_uint32 *min, gss_cred_id_t initiator_cred_handle, @@ -116,7 +121,6 @@ static OM_uint32 stub_gss_init_sec_context( char *token = NULL; const char *creds = NULL; - (void)initiator_cred_handle; (void)mech_type; (void)time_req; (void)input_chan_bindings; @@ -214,6 +218,16 @@ static OM_uint32 stub_gss_init_sec_context( if(strstr(creds, "NTLM")) ctx->have_ntlm = 1; + /* If a credential restricts allowed mechs, honour it */ + if(initiator_cred_handle != GSS_C_NO_CREDENTIAL) { + struct stub_gss_cred_id_t_desc *cred = + (struct stub_gss_cred_id_t_desc *)initiator_cred_handle; + if(!cred->allow_krb5) + ctx->have_krb5 = 0; + if(!cred->allow_ntlm) + ctx->have_ntlm = 0; + } + if(ctx->have_krb5) ctx->sent = STUB_GSS_KRB5; else if(ctx->have_ntlm) @@ -307,6 +321,174 @@ static OM_uint32 stub_gss_delete_sec_context( return GSS_S_COMPLETE; } + +/* NTLMSSP OID: 1.3.6.1.4.1.311.2.2.10 */ +static gss_OID_desc stub_ntlmssp_oid = { + 10, CURL_UNCONST("\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a") +}; + +static OM_uint32 stub_gss_inquire_context( + OM_uint32 *min, + struct stub_gss_ctx_id_t_desc *context, + gss_name_t *src_name, + gss_name_t *targ_name, + OM_uint32 *lifetime_rec, + gss_OID *mech_type, + OM_uint32 *ctx_flags, + int *locally_initiated, + int *open_context) +{ + (void)src_name; + (void)targ_name; + (void)lifetime_rec; + (void)ctx_flags; + (void)locally_initiated; + (void)open_context; + + if(!min) + return GSS_S_FAILURE; + + if(!context) { + *min = STUB_GSS_INVALID_CTX; + return GSS_S_FAILURE; + } + + *min = 0; + if(mech_type) { + switch(context->sent) { + case STUB_GSS_NTLM1: + case STUB_GSS_NTLM3: + *mech_type = &stub_ntlmssp_oid; + break; + default: + *mech_type = (gss_OID)&Curl_krb5_mech_oid; + break; + } + } + + return GSS_S_COMPLETE; +} +static OM_uint32 stub_gss_acquire_cred( + OM_uint32 *min, + gss_name_t desired_name, + OM_uint32 time_req, + gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *time_rec) +{ + (void)desired_name; + (void)time_req; + (void)desired_mechs; + (void)cred_usage; + (void)actual_mechs; + (void)time_rec; + + if(!min) + return GSS_S_FAILURE; + + *min = 0; + /* Allocate a stub credential that initially allows all mechanisms */ + if(output_cred_handle) { + struct stub_gss_cred_id_t_desc *cred = + curlx_calloc(1, sizeof(*cred)); + if(!cred) { + *min = STUB_GSS_NO_MEMORY; + return GSS_S_FAILURE; + } + cred->allow_krb5 = 1; + cred->allow_ntlm = 1; + *output_cred_handle = (gss_cred_id_t)cred; + } + return GSS_S_COMPLETE; +} + +static OM_uint32 stub_gss_indicate_mechs( + OM_uint32 *min, + gss_OID_set *mech_set) +{ + const char *creds; + OM_uint32 major; + + if(!min) + return GSS_S_FAILURE; + + *min = 0; + creds = getenv("CURL_STUB_GSS_CREDS"); + if(!creds) { + *min = STUB_GSS_INVALID_CREDS; + return GSS_S_FAILURE; + } + + major = gss_create_empty_oid_set(min, mech_set); + if(GSS_ERROR(major)) + return major; + + /* Always include Kerberos */ + gss_add_oid_set_member(min, (gss_OID)&Curl_krb5_mech_oid, mech_set); + + /* Include NTLM if the stub creds contain NTLM */ + if(strstr(creds, "NTLM")) + gss_add_oid_set_member(min, &stub_ntlmssp_oid, mech_set); + + return GSS_S_COMPLETE; +} + +#ifdef HAVE_GSS_SET_NEG_MECHS +static OM_uint32 stub_gss_set_neg_mechs( + OM_uint32 *min, + gss_cred_id_t cred_handle, + const gss_OID_set mech_set) +{ + struct stub_gss_cred_id_t_desc *cred; + size_t i; + int found_krb5 = 0; + int found_ntlm = 0; + + if(!min) + return GSS_S_FAILURE; + + *min = 0; + if(cred_handle == GSS_C_NO_CREDENTIAL) + return GSS_S_FAILURE; + + cred = (struct stub_gss_cred_id_t_desc *)cred_handle; + + /* Determine which mechs are in the allowed set */ + if(mech_set) { + for(i = 0; i < mech_set->count; i++) { + gss_OID oid = &mech_set->elements[i]; + if(oid->length == Curl_krb5_mech_oid.length && + !memcmp(oid->elements, Curl_krb5_mech_oid.elements, oid->length)) + found_krb5 = 1; + if(oid->length == stub_ntlmssp_oid.length && + !memcmp(oid->elements, stub_ntlmssp_oid.elements, oid->length)) + found_ntlm = 1; + } + } + + cred->allow_krb5 = found_krb5; + cred->allow_ntlm = found_ntlm; + return GSS_S_COMPLETE; +} +#endif /* HAVE_GSS_SET_NEG_MECHS */ + +static OM_uint32 stub_gss_release_cred( + OM_uint32 *min, + gss_cred_id_t *cred_handle) +{ + if(!min) + return GSS_S_FAILURE; + + *min = 0; + if(cred_handle && *cred_handle != GSS_C_NO_CREDENTIAL) { + curlx_free(*cred_handle); + *cred_handle = GSS_C_NO_CREDENTIAL; + } + return GSS_S_COMPLETE; +} + #endif /* CURL_GSS_STUB */ OM_uint32 Curl_gss_init_sec_context(struct Curl_easy *data, @@ -318,7 +500,8 @@ OM_uint32 Curl_gss_init_sec_context(struct Curl_easy *data, gss_buffer_t input_token, gss_buffer_t output_token, const bool mutual_auth, - OM_uint32 *ret_flags) + OM_uint32 *ret_flags, + gss_cred_id_t cred_handle) { OM_uint32 req_flags = GSS_C_REPLAY_FLAG; @@ -340,7 +523,7 @@ OM_uint32 Curl_gss_init_sec_context(struct Curl_easy *data, #ifdef CURL_GSS_STUB if(getenv("CURL_STUB_GSS_CREDS")) return stub_gss_init_sec_context(minor_status, - GSS_C_NO_CREDENTIAL, /* cred_handle */ + cred_handle, (struct stub_gss_ctx_id_t_desc **)context, target_name, mech_type, @@ -355,7 +538,7 @@ OM_uint32 Curl_gss_init_sec_context(struct Curl_easy *data, #endif /* CURL_GSS_STUB */ return gss_init_sec_context(minor_status, - GSS_C_NO_CREDENTIAL, /* cred_handle */ + cred_handle, context, target_name, mech_type, @@ -383,6 +566,80 @@ OM_uint32 Curl_gss_delete_sec_context(OM_uint32 *min, return gss_delete_sec_context(min, context, output_token); } +OM_uint32 Curl_gss_inquire_context(OM_uint32 *minor_status, + gss_ctx_id_t context, + gss_OID *mech_type) +{ +#ifdef CURL_GSS_STUB + if(getenv("CURL_STUB_GSS_CREDS")) + return stub_gss_inquire_context(minor_status, + (struct stub_gss_ctx_id_t_desc *)context, + NULL, NULL, NULL, mech_type, + NULL, NULL, NULL); +#endif /* CURL_GSS_STUB */ + + return gss_inquire_context(minor_status, context, + NULL, NULL, NULL, mech_type, + NULL, NULL, NULL); +} + +OM_uint32 Curl_gss_acquire_cred(OM_uint32 *minor_status, + gss_name_t desired_name, + OM_uint32 time_req, + gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *time_rec) +{ +#ifdef CURL_GSS_STUB + if(getenv("CURL_STUB_GSS_CREDS")) + return stub_gss_acquire_cred(minor_status, desired_name, time_req, + desired_mechs, cred_usage, + output_cred_handle, actual_mechs, time_rec); +#endif /* CURL_GSS_STUB */ + + return gss_acquire_cred(minor_status, desired_name, time_req, + desired_mechs, cred_usage, + output_cred_handle, actual_mechs, time_rec); +} + +OM_uint32 Curl_gss_indicate_mechs(OM_uint32 *minor_status, + gss_OID_set *mech_set) +{ +#ifdef CURL_GSS_STUB + if(getenv("CURL_STUB_GSS_CREDS")) + return stub_gss_indicate_mechs(minor_status, mech_set); +#endif /* CURL_GSS_STUB */ + + return gss_indicate_mechs(minor_status, mech_set); +} + +#ifdef HAVE_GSS_SET_NEG_MECHS +OM_uint32 Curl_gss_set_neg_mechs(OM_uint32 *minor_status, + gss_cred_id_t cred_handle, + const gss_OID_set mech_set) +{ +#ifdef CURL_GSS_STUB + if(getenv("CURL_STUB_GSS_CREDS")) + return stub_gss_set_neg_mechs(minor_status, cred_handle, mech_set); +#endif /* CURL_GSS_STUB */ + + return gss_set_neg_mechs(minor_status, cred_handle, mech_set); +} +#endif /* HAVE_GSS_SET_NEG_MECHS */ + +OM_uint32 Curl_gss_release_cred(OM_uint32 *minor_status, + gss_cred_id_t *cred_handle) +{ +#ifdef CURL_GSS_STUB + if(getenv("CURL_STUB_GSS_CREDS")) + return stub_gss_release_cred(minor_status, cred_handle); +#endif /* CURL_GSS_STUB */ + + return gss_release_cred(minor_status, cred_handle); +} + #ifdef CURLVERBOSE #define GSS_LOG_BUFFER_LEN 1024 static size_t display_gss_error(OM_uint32 status, int type, diff --git a/lib/curl_gssapi.h b/lib/curl_gssapi.h index fc3759ebcb..b33df77c17 100644 --- a/lib/curl_gssapi.h +++ b/lib/curl_gssapi.h @@ -41,12 +41,38 @@ OM_uint32 Curl_gss_init_sec_context(struct Curl_easy *data, gss_buffer_t input_token, gss_buffer_t output_token, const bool mutual_auth, - OM_uint32 *ret_flags); + OM_uint32 *ret_flags, + gss_cred_id_t cred_handle); OM_uint32 Curl_gss_delete_sec_context(OM_uint32 *min, gss_ctx_id_t *context, gss_buffer_t output_token); +OM_uint32 Curl_gss_inquire_context(OM_uint32 *minor_status, + gss_ctx_id_t context, + gss_OID *mech_type); + +OM_uint32 Curl_gss_acquire_cred(OM_uint32 *minor_status, + gss_name_t desired_name, + OM_uint32 time_req, + gss_OID_set desired_mechs, + gss_cred_usage_t cred_usage, + gss_cred_id_t *output_cred_handle, + gss_OID_set *actual_mechs, + OM_uint32 *time_rec); + +OM_uint32 Curl_gss_indicate_mechs(OM_uint32 *minor_status, + gss_OID_set *mech_set); + +#ifdef HAVE_GSS_SET_NEG_MECHS +OM_uint32 Curl_gss_set_neg_mechs(OM_uint32 *minor_status, + gss_cred_id_t cred_handle, + const gss_OID_set mech_set); +#endif + +OM_uint32 Curl_gss_release_cred(OM_uint32 *minor_status, + gss_cred_id_t *cred_handle); + #ifdef CURLVERBOSE /* Helper to log a GSS-API error status */ void Curl_gss_log_error(struct Curl_easy *data, const char *prefix, diff --git a/lib/curl_sspi.c b/lib/curl_sspi.c index b7dcb7d55c..1429f7143a 100644 --- a/lib/curl_sspi.c +++ b/lib/curl_sspi.c @@ -93,7 +93,7 @@ void Curl_sspi_global_cleanup(void) * Returns CURLE_OK on success. */ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, - SEC_WINNT_AUTH_IDENTITY *identity) + SEC_WINNT_AUTH_IDENTITY_EX *identity) { xcharp_u useranddomain; xcharp_u user, dup_user; @@ -105,6 +105,8 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, /* Initialize the identity */ memset(identity, 0, sizeof(*identity)); + identity->Version = SEC_WINNT_AUTH_IDENTITY_VERSION; + identity->Length = sizeof(*identity); useranddomain.tchar_ptr = curlx_convert_UTF8_to_tchar(userp); if(!useranddomain.tchar_ptr) @@ -195,7 +197,7 @@ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, * * identity [in/out] - The identity structure. */ -void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity) +void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY_EX *identity) { if(identity) { curlx_safefree(identity->User); diff --git a/lib/curl_sspi.h b/lib/curl_sspi.h index 2bd7eb4be8..992e01a9f2 100644 --- a/lib/curl_sspi.h +++ b/lib/curl_sspi.h @@ -34,14 +34,14 @@ void Curl_sspi_global_cleanup(void); /* This is used to populate the domain in an SSPI identity structure */ CURLcode Curl_override_sspi_http_realm(const char *chlg, - SEC_WINNT_AUTH_IDENTITY *identity); + SEC_WINNT_AUTH_IDENTITY_EX *identity); /* This is used to generate an SSPI identity structure */ CURLcode Curl_create_sspi_identity(const char *userp, const char *passwdp, - SEC_WINNT_AUTH_IDENTITY *identity); + SEC_WINNT_AUTH_IDENTITY_EX *identity); /* This is used to free an SSPI identity structure */ -void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY *identity); +void Curl_sspi_free_identity(SEC_WINNT_AUTH_IDENTITY_EX *identity); /* Forward-declaration of global variables defined in curl_sspi.c */ extern PSecurityFunctionTable Curl_pSecFn; diff --git a/lib/ldap.c b/lib/ldap.c index 63a40784a8..dac472d4c9 100644 --- a/lib/ldap.c +++ b/lib/ldap.c @@ -157,7 +157,7 @@ static ULONG ldap_win_bind_auth(LDAP *server, const char *user, const char *passwd, unsigned long authflags) { ULONG method = 0; - SEC_WINNT_AUTH_IDENTITY cred; + SEC_WINNT_AUTH_IDENTITY_EX cred; ULONG rc = LDAP_AUTH_METHOD_NOT_SUPPORTED; memset(&cred, 0, sizeof(cred)); diff --git a/lib/socks_gssapi.c b/lib/socks_gssapi.c index 9a5ad62f5c..c1cfba5b71 100644 --- a/lib/socks_gssapi.c +++ b/lib/socks_gssapi.c @@ -176,7 +176,8 @@ static CURLcode socks5_gss_auth_loop(struct Curl_cfilter *cf, gss_token, &gss_send_token, TRUE, - gss_ret_flags); + gss_ret_flags, + GSS_C_NO_CREDENTIAL); if(gss_token != GSS_C_NO_BUFFER) { curlx_safefree(gss_recv_token.value); diff --git a/lib/vauth/digest_sspi.c b/lib/vauth/digest_sspi.c index 305e367e17..c9b1432830 100644 --- a/lib/vauth/digest_sspi.c +++ b/lib/vauth/digest_sspi.c @@ -95,8 +95,8 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, CredHandle credentials; CtxtHandle context; PSecPkgInfo SecurityPackage; - SEC_WINNT_AUTH_IDENTITY identity; - SEC_WINNT_AUTH_IDENTITY *p_identity; + SEC_WINNT_AUTH_IDENTITY_EX identity; + SEC_WINNT_AUTH_IDENTITY_EX *p_identity; SecBuffer chlg_buf; SecBuffer resp_buf; SecBufferDesc chlg_desc; @@ -243,7 +243,7 @@ CURLcode Curl_auth_create_digest_md5_message(struct Curl_easy *data, * Returns CURLE_OK on success. */ CURLcode Curl_override_sspi_http_realm(const char *chlg, - SEC_WINNT_AUTH_IDENTITY *identity) + SEC_WINNT_AUTH_IDENTITY_EX *identity) { xcharp_u domain, dup_domain; @@ -465,8 +465,8 @@ CURLcode Curl_auth_create_digest_http_message(struct Curl_easy *data, if(!digest->http_context) { CredHandle credentials; - SEC_WINNT_AUTH_IDENTITY identity; - SEC_WINNT_AUTH_IDENTITY *p_identity; + SEC_WINNT_AUTH_IDENTITY_EX identity; + SEC_WINNT_AUTH_IDENTITY_EX *p_identity; SecBuffer resp_buf; SecBufferDesc resp_desc; unsigned long attrs; diff --git a/lib/vauth/krb5_gssapi.c b/lib/vauth/krb5_gssapi.c index 41c47c055d..6d9a125177 100644 --- a/lib/vauth/krb5_gssapi.c +++ b/lib/vauth/krb5_gssapi.c @@ -136,7 +136,8 @@ CURLcode Curl_auth_create_gssapi_user_message(struct Curl_easy *data, &input_token, &output_token, mutual_auth, - NULL); + NULL, + GSS_C_NO_CREDENTIAL); if(GSS_ERROR(major_status)) { if(output_token.value) diff --git a/lib/vauth/spnego_gssapi.c b/lib/vauth/spnego_gssapi.c index 1483b1f1e5..b2bc28fb3f 100644 --- a/lib/vauth/spnego_gssapi.c +++ b/lib/vauth/spnego_gssapi.c @@ -158,6 +158,57 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, } #endif +#ifdef HAVE_GSS_SET_NEG_MECHS + /* Acquire explicit credentials and restrict SPNEGO sub-mechanisms to + * exclude NTLM. We enumerate all available mechanisms and filter out + * the NTLMSSP OID, matching SSPI's "!ntlm". */ + if(nego->cred == GSS_C_NO_CREDENTIAL) { + /* OID 1.3.6.1.4.1.311.2.2.10 (NTLMSSP) */ + static const gss_OID_desc ntlmssp_oid = { + 10, CURL_UNCONST("\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a") + }; + gss_OID_set available_mechs = GSS_C_NO_OID_SET; + gss_OID_set filtered_mechs = GSS_C_NO_OID_SET; + + /* Acquire default credentials for SPNEGO */ + major_status = Curl_gss_acquire_cred(&minor_status, GSS_C_NO_NAME, + GSS_C_INDEFINITE, GSS_C_NO_OID_SET, + GSS_C_INITIATE, &nego->cred, NULL, NULL); + if(GSS_ERROR(major_status)) { + Curl_gss_log_error(data, "gss_acquire_cred() failed: ", + major_status, minor_status); + curlx_safefree(input_token.value); + return CURLE_AUTH_ERROR; + } + + /* Get all available mechanisms */ + major_status = Curl_gss_indicate_mechs(&minor_status, &available_mechs); + if(!GSS_ERROR(major_status)) { + /* Build a set excluding NTLMSSP */ + major_status = gss_create_empty_oid_set(&minor_status, &filtered_mechs); + if(!GSS_ERROR(major_status)) { + size_t i; + for(i = 0; i < available_mechs->count; i++) { + gss_OID oid = &available_mechs->elements[i]; + if(oid->length != ntlmssp_oid.length || + memcmp(oid->elements, ntlmssp_oid.elements, oid->length)) { + gss_add_oid_set_member(&minor_status, oid, &filtered_mechs); + } + } + /* Restrict SPNEGO to only use non-NTLM mechanisms */ + major_status = Curl_gss_set_neg_mechs(&minor_status, nego->cred, + filtered_mechs); + if(GSS_ERROR(major_status)) { + Curl_gss_log_error(data, "gss_set_neg_mechs() failed: ", + major_status, minor_status); + } + gss_release_oid_set(&minor_status, &filtered_mechs); + } + gss_release_oid_set(&minor_status, &available_mechs); + } + } +#endif /* HAVE_GSS_SET_NEG_MECHS */ + /* Generate our challenge-response message */ major_status = Curl_gss_init_sec_context(data, &minor_status, @@ -168,7 +219,8 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, &input_token, &output_token, TRUE, - NULL); + NULL, + nego->cred); /* Free the decoded challenge as it is not required anymore */ curlx_safefree(input_token.value); @@ -191,6 +243,29 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, return CURLE_AUTH_ERROR; } + /* Check if NTLM was selected and is disallowed */ + if(nego->context != GSS_C_NO_CONTEXT) { + /* OID 1.3.6.1.4.1.311.2.2.10 (NTLMSSP) */ + static const gss_OID_desc ntlmssp_oid = { + 10, CURL_UNCONST("\x2b\x06\x01\x04\x01\x82\x37\x02\x02\x0a") + }; + OM_uint32 inquire_major, inquire_minor; + gss_OID mech_type = GSS_C_NO_OID; + + inquire_major = Curl_gss_inquire_context(&inquire_minor, + nego->context, + &mech_type); + if(!GSS_ERROR(inquire_major) && mech_type && + mech_type->length == ntlmssp_oid.length && + !memcmp(mech_type->elements, ntlmssp_oid.elements, + ntlmssp_oid.length)) { + infof(data, "SPNEGO chose NTLM, but NTLM is not allowed"); + gss_release_buffer(&unused_status, &output_token); + Curl_auth_cleanup_spnego(nego); + return CURLE_AUTH_ERROR; + } + } + /* Free previous token */ if(nego->output_token.length && nego->output_token.value) gss_release_buffer(&unused_status, &nego->output_token); @@ -280,6 +355,12 @@ void Curl_auth_cleanup_spnego(struct negotiatedata *nego) nego->spn = GSS_C_NO_NAME; } + /* Free our credentials */ + if(nego->cred != GSS_C_NO_CREDENTIAL) { + Curl_gss_release_cred(&minor_status, &nego->cred); + nego->cred = GSS_C_NO_CREDENTIAL; + } + /* Reset any variables */ nego->status = 0; nego->noauthpersist = FALSE; diff --git a/lib/vauth/spnego_sspi.c b/lib/vauth/spnego_sspi.c index b7d82c04dd..da9d7b023b 100644 --- a/lib/vauth/spnego_sspi.c +++ b/lib/vauth/spnego_sspi.c @@ -148,6 +148,32 @@ CURLcode Curl_auth_decode_spnego_message(struct Curl_easy *data, /* Use the current Windows user */ nego->p_identity = NULL; + /* Exclude NTLM from SPNEGO negotiation via the PackageList field */ + if(!nego->p_identity) { + memset(&nego->identity, 0, sizeof(nego->identity)); + nego->identity.Version = SEC_WINNT_AUTH_IDENTITY_VERSION; + nego->identity.Length = sizeof(nego->identity); + nego->identity.Flags = +#ifdef UNICODE + SEC_WINNT_AUTH_IDENTITY_UNICODE; +#else + SEC_WINNT_AUTH_IDENTITY_ANSI; +#endif + nego->p_identity = &nego->identity; + } + + /* Use the special name "!ntlm" to prevent NTLM from being used: + * https://learn.microsoft.com/en-us/windows/win32/api/sspi/ns-sspi-sec_winnt_auth_identity_exa + */ +#ifdef UNICODE + nego->identity.PackageList = + (unsigned short *)CURL_UNCONST(TEXT("!ntlm")); +#else + nego->identity.PackageList = + (unsigned char *)CURL_UNCONST(TEXT("!ntlm")); +#endif + nego->identity.PackageListLength = 5; + /* Allocate our credentials handle */ nego->credentials = curlx_calloc(1, sizeof(CredHandle)); if(!nego->credentials) diff --git a/lib/vauth/vauth.h b/lib/vauth/vauth.h index 0f82f92945..f8ec563e92 100644 --- a/lib/vauth/vauth.h +++ b/lib/vauth/vauth.h @@ -169,8 +169,8 @@ struct ntlmdata { #endif CredHandle *credentials; CtxtHandle *context; - SEC_WINNT_AUTH_IDENTITY identity; - SEC_WINNT_AUTH_IDENTITY *p_identity; + SEC_WINNT_AUTH_IDENTITY_EX identity; + SEC_WINNT_AUTH_IDENTITY_EX *p_identity; size_t token_max; BYTE *output_token; BYTE *input_token; @@ -236,8 +236,8 @@ struct kerberos5data { CredHandle *credentials; CtxtHandle *context; TCHAR *spn; - SEC_WINNT_AUTH_IDENTITY identity; - SEC_WINNT_AUTH_IDENTITY *p_identity; + SEC_WINNT_AUTH_IDENTITY_EX identity; + SEC_WINNT_AUTH_IDENTITY_EX *p_identity; size_t token_max; BYTE *output_token; #else @@ -291,6 +291,7 @@ struct negotiatedata { OM_uint32 status; gss_ctx_id_t context; gss_name_t spn; + gss_cred_id_t cred; gss_buffer_desc output_token; #ifdef GSS_C_CHANNEL_BOUND_FLAG struct dynbuf channel_binding_data; @@ -303,8 +304,8 @@ struct negotiatedata { SECURITY_STATUS status; CredHandle *credentials; CtxtHandle *context; - SEC_WINNT_AUTH_IDENTITY identity; - SEC_WINNT_AUTH_IDENTITY *p_identity; + SEC_WINNT_AUTH_IDENTITY_EX identity; + SEC_WINNT_AUTH_IDENTITY_EX *p_identity; TCHAR *spn; size_t token_max; BYTE *output_token; diff --git a/tests/data/Makefile.am b/tests/data/Makefile.am index 728858dafa..76ac5be1bf 100644 --- a/tests/data/Makefile.am +++ b/tests/data/Makefile.am @@ -252,7 +252,7 @@ test2056 test2057 test2058 test2059 test2060 test2061 test2062 test2063 \ test2064 test2065 test2066 test2067 test2068 test2069 test2070 test2071 \ test2072 test2073 test2074 test2075 test2076 test2077 test2078 test2079 \ test2080 test2081 test2082 test2083 test2084 test2085 test2086 test2087 \ -test2088 test2089 test2090 test2091 test2092 test2093 \ +test2088 test2089 test2090 test2091 test2092 test2093 test2094 \ test2100 test2101 test2102 test2103 test2104 test2105 test2106 test2107 \ test2108 test2109 test2110 test2113 test2114 test2115 test2116 test2117 \ \ diff --git a/tests/data/test2057 b/tests/data/test2057 index 18ce33d947..d2ca3b7968 100644 --- a/tests/data/test2057 +++ b/tests/data/test2057 @@ -5,45 +5,17 @@ HTTP HTTP GET HTTP Negotiate auth (stub ntlm) +SPNEGO NTLM disallowed # Server-side - - -HTTP/1.1 401 Authorization Required -Server: Microsoft-IIS/7.0 -Content-Type: text/html; charset=iso-8859-1 -WWW-Authenticate: Negotiate Qw== -Content-Length: 19 + +HTTP/1.1 200 OK swsclose +Content-Length: 23 -Still not yet sir! - - - -HTTP/1.1 200 Things are fine in server land -Server: Microsoft-IIS/7.0 -Content-Type: text/html; charset=iso-8859-1 -WWW-Authenticate: Negotiate RA== -Content-Length: 15 - -Nice auth sir! - - -HTTP/1.1 401 Authorization Required -Server: Microsoft-IIS/7.0 -Content-Type: text/html; charset=iso-8859-1 -WWW-Authenticate: Negotiate Qw== -Content-Length: 19 - -HTTP/1.1 200 Things are fine in server land -Server: Microsoft-IIS/7.0 -Content-Type: text/html; charset=iso-8859-1 -WWW-Authenticate: Negotiate RA== -Content-Length: 15 - -Nice auth sir! - +This IS the real page! + # Client-side @@ -52,7 +24,7 @@ Nice auth sir! http -HTTP Negotiate authentication (stub NTLM) +HTTP Negotiate authentication blocked for stub NTLM credentials GSS-API @@ -68,16 +40,15 @@ CURL_STUB_GSS_CREDS="NTLM_Alice" # Verify data after the test has been "shot" + +0 + +# NTLM is blocked within SPNEGO, so when only NTLM credentials are +# available, negotiate auth silently fails and the request is sent +# without any Authorization header. GET /%TESTNUMBER HTTP/1.1 Host: %HOSTIP:%HTTPPORT -Authorization: Negotiate %b64["NTLM_Alice":HTTP@127.0.0.1:2:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA]b64% -User-Agent: curl/%VERSION -Accept: */* - -GET /%TESTNUMBER HTTP/1.1 -Host: %HOSTIP:%HTTPPORT -Authorization: Negotiate %b64["NTLM_Alice":HTTP@127.0.0.1:3:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA]b64% User-Agent: curl/%VERSION Accept: */* diff --git a/tests/data/test2094 b/tests/data/test2094 new file mode 100644 index 0000000000..57ded4456e --- /dev/null +++ b/tests/data/test2094 @@ -0,0 +1,68 @@ + + + + +HTTP +HTTP GET +HTTP Negotiate auth (stub krb5) +SPNEGO NTLM disallowed + + + +# Server-side + + +HTTP/1.1 200 Things are fine in server land +Server: Microsoft-IIS/7.0 +Content-Type: text/html; charset=iso-8859-1 +WWW-Authenticate: Negotiate RA== +Content-Length: 15 + +Nice auth sir! + + +HTTP/1.1 200 Things are fine in server land +Server: Microsoft-IIS/7.0 +Content-Type: text/html; charset=iso-8859-1 +WWW-Authenticate: Negotiate RA== +Content-Length: 15 + +Nice auth sir! + + + +# Client-side + + +http + + +SPNEGO with Kerberos still works when NTLM is blocked + + +GSS-API +Debug + + +CURL_STUB_GSS_CREDS="KRB5_Alice" + + +--negotiate http://%HOSTIP:%HTTPPORT/%TESTNUMBER + + + +# Verify data after the test has been "shot" + + +0 + + +GET /%TESTNUMBER HTTP/1.1 +Host: %HOSTIP:%HTTPPORT +Authorization: Negotiate %b64["KRB5_Alice":HTTP@127.0.0.1:1:AAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA]b64% +User-Agent: curl/%VERSION +Accept: */* + + + + diff --git a/tests/valgrind.supp b/tests/valgrind.supp index aad7255248..026723d5d1 100644 --- a/tests/valgrind.supp +++ b/tests/valgrind.supp @@ -128,3 +128,14 @@ fun:inet_pton6 fun:ipv6_parse } + +{ + mit-krb5-gss_display_status-internal-leak + Memcheck:Leak + match-leak-kinds: definite + fun:realloc + ... + fun:gss_display_status + fun:display_gss_error + fun:Curl_gss_log_error +} From 27a4557c9ea87f1961741fb728387261387b398c Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 27 Jul 2026 23:56:44 +0200 Subject: [PATCH 03/15] EXPERIMENTAL.md: We do not accept vuln reports for experimental features Closes #22411 --- docs/EXPERIMENTAL.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/docs/EXPERIMENTAL.md b/docs/EXPERIMENTAL.md index ff37422172..c5083e9f65 100644 --- a/docs/EXPERIMENTAL.md +++ b/docs/EXPERIMENTAL.md @@ -21,6 +21,8 @@ Experimental support in curl means: to our API/ABI rules as we do for regular features, as long as it is marked experimental. 5. Experimental features are clearly marked so in documentation. Beware. +6. Vulnerabilities in experimental features are not considered security + problems; please report them as regular bugs/feedback instead. ## Graduation From c7328740ecad6e5549c210366b8403eca29b4123 Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Tue, 28 Jul 2026 11:53:42 +0200 Subject: [PATCH 04/15] lib2405: adjust for non-threaded builds - Attempt to fix the flakiness set in 9726fc8259ad7ebf1682 - Reduce macro use Closes #22414 --- tests/data/test2405 | 1 - tests/data/test2407 | 1 - tests/libtest/lib2405.c | 69 ++++++++++++++++++++++++++--------------- 3 files changed, 44 insertions(+), 27 deletions(-) diff --git a/tests/data/test2405 b/tests/data/test2405 index 0d64ec458a..6ccb6ba394 100644 --- a/tests/data/test2405 +++ b/tests/data/test2405 @@ -4,7 +4,6 @@ multi HTTP -flaky diff --git a/tests/data/test2407 b/tests/data/test2407 index 33555a8502..b9f17bb22f 100644 --- a/tests/data/test2407 +++ b/tests/data/test2407 @@ -5,7 +5,6 @@ multi HTTP HTTP/2 -flaky diff --git a/tests/libtest/lib2405.c b/tests/libtest/lib2405.c index 412faf45a0..6d98183a83 100644 --- a/tests/libtest/lib2405.c +++ b/tests/libtest/lib2405.c @@ -41,24 +41,6 @@ /* ---------------------------------------------------------------- */ -#define test_check(expected_fds) \ - if(result != CURLE_OK) { \ - curl_mfprintf(stderr, "test failed with code: %d\n", (int)result); \ - goto test_cleanup; \ - } \ - else if(fd_count != (expected_fds)) { \ - curl_mfprintf(stderr, "Max number of waitfds: %u not as expected: %u\n", \ - fd_count, expected_fds); \ - result = TEST_ERR_FAILURE; \ - goto test_cleanup; \ - } - -#define test_run_check(option, expected_fds) \ - do { \ - result = test_run(URL, option, &fd_count); \ - test_check(expected_fds); \ - } while(0) - /* ---------------------------------------------------------------- */ enum { @@ -302,6 +284,22 @@ test_cleanup: return result; } +static CURLcode test_run_check(const char *URL, long option, + unsigned int expected_fds) +{ + unsigned int fd_count = 0; + CURLcode result = test_run(URL, option, &fd_count); + if(result) + curl_mfprintf(stderr, "test failed with code: %d\n", (int)result); + else if(fd_count != expected_fds) { + curl_mfprintf(stderr, + "Max number of waitfds: %u not as expected: %u\n", + fd_count, expected_fds); + result = TEST_ERR_FAILURE; + } + return result; +} + static CURLcode empty_multi_test(void) { CURLMcode mresult = CURLM_OK; @@ -360,29 +358,50 @@ test_cleanup: return result; } +static unsigned int uses_threaded(void) +{ + curl_version_info_data *ver = curl_version_info(CURLVERSION_NOW); + const char * const *n = ver->feature_names; + int i; + unsigned int uses = 0; + /* the 'asyn-rr' feature tells us libcurl uses the threaded resolver */ + for(i = 0; n[i]; i++) { + if(!strcmp("asyn-rr", n[i])) + uses = 1; + } + /* if not using asyn-rr, check if doing asynch DNS without using c-ares */ + if(!uses && (ver->features & CURL_VERSION_ASYNCHDNS) && !ver->ares) + uses = 1; + return uses; +} + static CURLcode test_lib2405(const char *URL) { CURLcode result = CURLE_OK; - unsigned int fd_count = 0; + int uses_threaded_resolver; global_init(CURL_GLOBAL_ALL); + uses_threaded_resolver = uses_threaded(); + /* Testing curl_multi_waitfds on empty and not started handles */ result = empty_multi_test(); if(result != CURLE_OK) goto test_cleanup; if(testnum == 2405) { - /* HTTP1, expected 3 waitfds - one for each transfer + wakeup */ - test_run_check(TEST_USE_HTTP1, 3U); + /* HTTP1, one for each transfer + possible wakeup */ + result = test_run_check(URL, TEST_USE_HTTP1, 2 + uses_threaded_resolver); } #ifdef USE_HTTP2 else { /* 2407 */ - /* HTTP2, expected 3 waitfds - one for each transfer + wakeup */ - test_run_check(TEST_USE_HTTP2, 3U); + /* HTTP2, one for each transfer + possible wakeup */ + result = test_run_check(URL, TEST_USE_HTTP2, 2 + uses_threaded_resolver); - /* HTTP2 with multiplexing, expected 2 waitfds - transfers + wakeup */ - test_run_check(TEST_USE_HTTP2_MPLEX, 2U); + /* HTTP2 with multiplexing, expected one waitfds + possible wakeup */ + if(!result) + result = test_run_check(URL, TEST_USE_HTTP2_MPLEX, + 1 + uses_threaded_resolver); } #endif From 573a6ec16b5822ee209d46c490f7e4200036c7dd Mon Sep 17 00:00:00 2001 From: Daniel Stenberg Date: Mon, 27 Jul 2026 16:05:38 +0200 Subject: [PATCH 05/15] urlapi: improved return codes - add CURLUE_BACKSLASH that can be returned when a backslash was used where a forward one probably was intended. - make CURLUE_NO_HOST higher priority than port number errors for URLs without hostname. Like in "http://::1" - shortened some URL parser error strings Extend test 1560 to verify. Reported-by: kit-ty-kate on github Fixes #22337 Closes #22408 --- docs/libcurl/libcurl-errors.md | 5 +++++ docs/libcurl/symbols-in-versions | 1 + include/curl/urlapi.h | 1 + lib/strerror.c | 23 +++++++++++++---------- lib/urlapi.c | 16 +++++++++++----- projects/OS400/curl.inc.in | 2 ++ tests/data/test1538 | 23 ++++++++++++----------- tests/libtest/lib1560.c | 10 +++++++++- 8 files changed, 54 insertions(+), 27 deletions(-) diff --git a/docs/libcurl/libcurl-errors.md b/docs/libcurl/libcurl-errors.md index c658361a79..6f348eb581 100644 --- a/docs/libcurl/libcurl-errors.md +++ b/docs/libcurl/libcurl-errors.md @@ -724,6 +724,11 @@ libcurl lacks IDN support. A value or data field is larger than allowed. +## CURLUE_BACKSLASH (32) + +Found a backslash character where a forward slash was expected. URL separators +are forward slashes (`/`), not backslashes (`\`). + # CURLHcode The header interface returns a *CURLHcode* to indicate when an error has diff --git a/docs/libcurl/symbols-in-versions b/docs/libcurl/symbols-in-versions index a3d92a2637..65279d6426 100644 --- a/docs/libcurl/symbols-in-versions +++ b/docs/libcurl/symbols-in-versions @@ -1113,6 +1113,7 @@ CURLU_PUNY2IDN 8.3.0 CURLU_PUNYCODE 7.88.0 CURLU_URLDECODE 7.62.0 CURLU_URLENCODE 7.62.0 +CURLUE_BACKSLASH 8.22.0 CURLUE_BAD_FILE_URL 7.81.0 CURLUE_BAD_FRAGMENT 7.81.0 CURLUE_BAD_HANDLE 7.62.0 diff --git a/include/curl/urlapi.h b/include/curl/urlapi.h index b1f3a2316b..02553dfebf 100644 --- a/include/curl/urlapi.h +++ b/include/curl/urlapi.h @@ -64,6 +64,7 @@ typedef enum { CURLUE_BAD_USER, /* 29 */ CURLUE_LACKS_IDN, /* 30 */ CURLUE_TOO_LARGE, /* 31 */ + CURLUE_BACKSLASH, /* 32 */ CURLUE_LAST } CURLUcode; diff --git a/lib/strerror.c b/lib/strerror.c index 7b6dc02127..6fc801dc61 100644 --- a/lib/strerror.c +++ b/lib/strerror.c @@ -452,34 +452,34 @@ const char *curl_url_strerror(CURLUcode error) return "An unknown part ID was passed to a URL API function"; case CURLUE_NO_SCHEME: - return "No scheme part in the URL"; + return "No scheme present"; case CURLUE_NO_USER: - return "No user part in the URL"; + return "No user present"; case CURLUE_NO_PASSWORD: - return "No password part in the URL"; + return "No password present"; case CURLUE_NO_OPTIONS: - return "No options part in the URL"; + return "No options present"; case CURLUE_NO_HOST: - return "No host part in the URL"; + return "No host present"; case CURLUE_NO_PORT: - return "No port part in the URL"; + return "No port number present"; case CURLUE_NO_QUERY: - return "No query part in the URL"; + return "No query present"; case CURLUE_NO_FRAGMENT: - return "No fragment part in the URL"; + return "No fragment present"; case CURLUE_NO_ZONEID: - return "No zoneid part in the URL"; + return "No zoneid present"; case CURLUE_BAD_LOGIN: - return "Bad login part"; + return "Bad login"; case CURLUE_BAD_IPV6: return "Bad IPv6 address"; @@ -517,6 +517,9 @@ const char *curl_url_strerror(CURLUcode error) case CURLUE_TOO_LARGE: return "A value or data field is larger than allowed"; + case CURLUE_BACKSLASH: + return "Found a backslash where a forward slash was expected"; + case CURLUE_LAST: break; } diff --git a/lib/urlapi.c b/lib/urlapi.c index cbb16a43c4..35251053ad 100644 --- a/lib/urlapi.c +++ b/lib/urlapi.c @@ -382,6 +382,7 @@ UNITTEST CURLUcode parse_port(struct Curl_URL *u, struct dynbuf *host, if(portptr) { curl_off_t port; size_t keep = portptr - hostname; + int rc; /* Browser behavior adaptation. If there is a colon with no digits after, cut off the name there which makes us ignore the colon and use the @@ -393,8 +394,14 @@ UNITTEST CURLUcode parse_port(struct Curl_URL *u, struct dynbuf *host, portptr++; if(!*portptr) return has_scheme ? CURLUE_OK : CURLUE_BAD_PORT_NUMBER; - - if(curlx_str_number(&portptr, &port, 0xffff) || *portptr) + if(*portptr == '\\') + return CURLUE_BACKSLASH; + rc = curlx_str_number(&portptr, &port, 0xffff); + if(rc) + return CURLUE_BAD_PORT_NUMBER; + else if(*portptr == '\\') + return CURLUE_BACKSLASH; + else if(*portptr) return CURLUE_BAD_PORT_NUMBER; u->portnum = (uint16_t)port; @@ -666,12 +673,11 @@ static CURLUcode parse_authority(struct Curl_URL *u, } uc = parse_port(u, host, has_scheme); - if(uc) - return uc; if(!curlx_dyn_len(host)) + /* this makes no-host errors override port number problems */ uc = CURLUE_NO_HOST; - else + if(!uc) uc = urldecode_host(host); if(uc) return uc; diff --git a/projects/OS400/curl.inc.in b/projects/OS400/curl.inc.in index f97f26e012..d048663f72 100644 --- a/projects/OS400/curl.inc.in +++ b/projects/OS400/curl.inc.in @@ -2340,6 +2340,8 @@ d c 30 d CURLUE_TOO_LARGE... d c 31 + d CURLUE_BACKSLASH... + d c 32 * d CURLUPart s 10i 0 based(######ptr######) Enum d CURLUPART_URL c 0 diff --git a/tests/data/test1538 b/tests/data/test1538 index 51580576ee..bdfe9478ed 100644 --- a/tests/data/test1538 +++ b/tests/data/test1538 @@ -163,20 +163,20 @@ u6: URL decode error, most likely because of rubbish in the input u7: A memory function failed u8: Credentials was passed in the URL when prohibited u9: An unknown part ID was passed to a URL API function -u10: No scheme part in the URL -u11: No user part in the URL -u12: No password part in the URL -u13: No options part in the URL -u14: No host part in the URL -u15: No port part in the URL -u16: No query part in the URL -u17: No fragment part in the URL -u18: No zoneid part in the URL +u10: No scheme present +u11: No user present +u12: No password present +u13: No options present +u14: No host present +u15: No port number present +u16: No query present +u17: No fragment present +u18: No zoneid present u19: Bad file:// URL u20: Bad fragment u21: Bad hostname u22: Bad IPv6 address -u23: Bad login part +u23: Bad login u24: Bad password u25: Bad path u26: Bad query @@ -185,7 +185,8 @@ u28: Unsupported number of slashes following scheme u29: Bad user u30: libcurl lacks IDN support u31: A value or data field is larger than allowed -u32: CURLUcode unknown +u32: Found a backslash where a forward slash was expected +u33: CURLUcode unknown diff --git a/tests/libtest/lib1560.c b/tests/libtest/lib1560.c index 0b20780b7e..1c8aabfd5b 100644 --- a/tests/libtest/lib1560.c +++ b/tests/libtest/lib1560.c @@ -153,6 +153,14 @@ struct clearurlcase { }; static const struct testcase get_parts_list[] = { + /* backslash mistakes */ + {"http:\\\\hostname", "", + CURLU_GUESS_SCHEME, 0, CURLUE_BACKSLASH }, + {"http:\\\\hostname:1234", "", + CURLU_GUESS_SCHEME, 0, CURLUE_BACKSLASH }, + {"http://hostname:1111\\path", "", + 0, 0, CURLUE_BACKSLASH }, + /* non-supported URL without hostname */ {"weird:///path", "weird | [11] | [12] | [13] | | [15] | /path | [16] | [17]", @@ -753,7 +761,7 @@ static const struct urltestcase get_url_list[] = { /* malformed unbracketed IPv6 */ {"https://fe80:8080::1/", "", 0, 0, CURLUE_BAD_PORT_NUMBER}, - {"https://::1/", "", 0, 0, CURLUE_BAD_PORT_NUMBER}, + {"https://::1/", "", 0, 0, CURLUE_NO_HOST}, /* Empty host with standard schemes */ {"http:///", "", 0, 0, CURLUE_NO_HOST}, From e1450d8fdaf05f27ec75eb15df303fe931755a59 Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Thu, 23 Jul 2026 01:50:06 +0200 Subject: [PATCH 06/15] tidy-up: use more `static`, `sizeof()`, `char[]`, double-const - make `const` data `static`, where missing and possible. - replace `strlen()` on literal or const strings with `sizeof()`. While the latter is optimized by popular C compiler, e.g. MSVC only does it with `/O2`. - replace magic numbers with `sizeof()`, where missing. - introduce `CURL_CSTRLEN()` macro for `sizeof(char[]) - 1`. - use `CURL_CSTRLEN()` macro. - move `const` before integer types, where missing. - replace `char *var` with `var[]`, where missing and possible. - use double const, where missing. `static const char *` -> `static const char * const`. - lib1514: constify pointers. - unit3205: drop redundant cast, avoid another one. - unit1666: map `OID()` macro to identical `STRCONST()`. Closes #22406 --- CMake/CurlTests.c | 2 +- docs/examples/10-at-a-time.c | 2 +- docs/examples/crawler.c | 2 +- docs/examples/ephiperfifo.c | 6 ++- docs/examples/evhiperfifo.c | 6 ++- docs/examples/ghiper.c | 6 ++- docs/examples/hiperfifo.c | 6 ++- docs/examples/imap-append.c | 4 +- docs/examples/maxconnects.c | 2 +- docs/examples/postinmemory.c | 4 +- docs/examples/sendrecv.c | 4 +- docs/examples/sepheaders.c | 4 +- docs/examples/sftpuploadresume.c | 4 +- docs/examples/simplepost.c | 4 +- docs/examples/simplessl.c | 6 +-- docs/examples/smtp-authzid.c | 2 +- docs/examples/smtp-mail.c | 2 +- docs/examples/smtp-mime.c | 4 +- docs/examples/smtp-multi.c | 2 +- docs/examples/smtp-ssl.c | 2 +- docs/examples/smtp-tls.c | 2 +- docs/examples/synctime.c | 4 +- docs/examples/url2file.c | 2 +- docs/examples/websocket-updown.c | 4 +- lib/cf-h1-proxy.c | 4 +- lib/cf-h2-proxy.c | 2 +- lib/curl_setup.h | 6 ++- lib/dict.c | 12 +++--- lib/http.c | 2 +- lib/http2.c | 4 +- lib/http_aws_sigv4.c | 4 +- lib/http_digest.c | 2 +- lib/http_negotiate.c | 2 +- lib/http_ntlm.c | 2 +- lib/http_proxy.c | 6 +-- lib/imap.c | 2 +- lib/ldap.c | 4 +- lib/mqtt.c | 4 +- lib/progress.c | 2 +- lib/smb.c | 9 +++-- lib/tftp.c | 4 +- lib/vquic/cf-quiche.c | 7 ++-- lib/vssh/libssh2.c | 2 +- lib/vtls/cipher_suite.c | 2 +- lib/vtls/gtls.c | 6 +-- lib/vtls/keylog.h | 2 +- lib/vtls/openssl.c | 24 +++++------ lib/vtls/schannel.c | 12 +++--- lib/vtls/schannel_verify.c | 4 +- lib/vtls/vtls.c | 4 +- lib/vtls/wolfssl.c | 8 ++-- scripts/schemetable.c | 2 +- src/curlinfo.c | 2 +- src/tool_doswin.c | 6 +-- src/tool_easysrc.c | 2 +- src/tool_formparse.c | 8 ++-- src/tool_getparam.c | 2 +- src/tool_helpers.c | 4 +- src/tool_libinfo.c | 2 +- src/tool_paramhlp.c | 2 +- src/tool_progress.c | 2 +- src/var.c | 10 ++--- .../http/testenv/mod_curltest/mod_curltest.c | 2 +- tests/libtest/lib1514.c | 6 +-- tests/libtest/lib1517.c | 2 +- tests/libtest/lib1520.c | 2 +- tests/libtest/lib1525.c | 2 +- tests/libtest/lib1526.c | 2 +- tests/libtest/lib1527.c | 2 +- tests/libtest/lib1531.c | 4 +- tests/libtest/lib1537.c | 6 ++- tests/libtest/lib1554.c | 2 +- tests/libtest/lib1560.c | 4 +- tests/libtest/lib1576.c | 5 ++- tests/libtest/lib1591.c | 2 +- tests/libtest/lib1598.c | 4 +- tests/libtest/lib1662.c | 2 +- tests/libtest/lib1901.c | 2 +- tests/libtest/lib1940.c | 2 +- tests/libtest/lib1948.c | 6 +-- tests/libtest/lib1965.c | 2 +- tests/libtest/lib3102.c | 8 ++-- tests/libtest/lib505.c | 4 +- tests/libtest/lib508.c | 2 +- tests/libtest/lib536.c | 2 +- tests/libtest/lib544.c | 2 +- tests/libtest/lib547.c | 2 +- tests/libtest/lib554.c | 4 +- tests/libtest/lib555.c | 2 +- tests/libtest/lib571.c | 2 +- tests/libtest/lib643.c | 4 +- tests/libtest/lib654.c | 2 +- tests/libtest/lib655.c | 2 +- tests/libtest/lib667.c | 2 +- tests/libtest/lib668.c | 2 +- tests/libtest/lib677.c | 6 +-- tests/libtest/lib757.c | 2 +- tests/server/mqttd.c | 8 ++-- tests/server/rtspd.c | 38 +++++++++--------- tests/server/socksd.c | 4 +- tests/server/sws.c | 40 ++++++++++--------- tests/tunit/tool1720.c | 2 +- tests/unit/unit1303.c | 2 +- tests/unit/unit1395.c | 2 +- tests/unit/unit1396.c | 4 +- tests/unit/unit1398.c | 2 +- tests/unit/unit1625.c | 4 +- tests/unit/unit1627.c | 4 +- tests/unit/unit1650.c | 12 +++--- tests/unit/unit1655.c | 6 +-- tests/unit/unit1664.c | 24 +++++------ tests/unit/unit1666.c | 2 +- tests/unit/unit1675.c | 12 +++--- tests/unit/unit2603.c | 14 +++---- tests/unit/unit3200.c | 2 +- tests/unit/unit3205.c | 7 ++-- tests/unit/unit3400.c | 32 ++++++++------- 117 files changed, 311 insertions(+), 287 deletions(-) diff --git a/CMake/CurlTests.c b/CMake/CurlTests.c index f43521bfd6..e8117410fd 100644 --- a/CMake/CurlTests.c +++ b/CMake/CurlTests.c @@ -65,7 +65,7 @@ int main(void) #include int main(void) { - const char *address = "localhost"; + static const char address[] = "localhost"; struct hostent h; int rc = 0; #if defined(HAVE_GETHOSTBYNAME_R_3) || \ diff --git a/docs/examples/10-at-a-time.c b/docs/examples/10-at-a-time.c index d0982e0d41..34572e438b 100644 --- a/docs/examples/10-at-a-time.c +++ b/docs/examples/10-at-a-time.c @@ -30,7 +30,7 @@ #include -static const char *urls[] = { +static const char * const urls[] = { "https://01.example/", "https://02.example/", "https://03.example/", diff --git a/docs/examples/crawler.c b/docs/examples/crawler.c index 21cdb5fcff..595375614e 100644 --- a/docs/examples/crawler.c +++ b/docs/examples/crawler.c @@ -47,7 +47,7 @@ static int max_total = 20000; static int max_requests = 500; static size_t max_link_per_page = 5; static int follow_relative_links = 0; -static const char *start_page = "https://www.reuters.com/"; +static const char start_page[] = "https://www.reuters.com/"; static int pending_interrupt = 0; static void sighandler(int dummy) diff --git a/docs/examples/ephiperfifo.c b/docs/examples/ephiperfifo.c index 292bfc741e..de86690ef4 100644 --- a/docs/examples/ephiperfifo.c +++ b/docs/examples/ephiperfifo.c @@ -303,7 +303,9 @@ static int sock_cb(CURL *e, curl_socket_t s, int what, void *cbp, void *sockp) { struct GlobalInfo *g = (struct GlobalInfo *)cbp; struct SockInfo *fdp = (struct SockInfo *)sockp; - const char *whatstr[] = { "none", "IN", "OUT", "INOUT", "REMOVE" }; + static const char * const whatstr[] = { + "none", "IN", "OUT", "INOUT", "REMOVE" + }; fprintf(MSG_OUT, "socket callback: s=%d e=%p what=%s ", s, e, whatstr[what]); if(what == CURL_POLL_REMOVE) { @@ -407,7 +409,7 @@ static void fifo_cb(struct GlobalInfo *g, int revents) static int init_fifo(struct GlobalInfo *g) { struct stat st; - static const char *fifo = "hiper.fifo"; + static const char fifo[] = "hiper.fifo"; curl_socket_t sockfd; struct epoll_event epev; diff --git a/docs/examples/evhiperfifo.c b/docs/examples/evhiperfifo.c index 079eab1e8a..32f92f9415 100644 --- a/docs/examples/evhiperfifo.c +++ b/docs/examples/evhiperfifo.c @@ -267,7 +267,9 @@ static int sock_cb(CURL *e, curl_socket_t s, int what, void *cbp, void *sockp) { struct GlobalInfo *g = (struct GlobalInfo *)cbp; struct SockInfo *fdp = (struct SockInfo *)sockp; - const char *whatstr[] = { "none", "IN", "OUT", "INOUT", "REMOVE" }; + static const char * const whatstr[] = { + "none", "IN", "OUT", "INOUT", "REMOVE" + }; printf("%s e %p s %d what %d cbp %p sockp %p\n", __PRETTY_FUNCTION__, e, s, what, cbp, sockp); @@ -378,7 +380,7 @@ static void fifo_cb(EV_P_ struct ev_io *w, int revents) static int init_fifo(struct GlobalInfo *g) { struct stat st; - static const char *fifo = "hiper.fifo"; + static const char fifo[] = "hiper.fifo"; curl_socket_t sockfd; fprintf(MSG_OUT, "Creating named pipe \"%s\"\n", fifo); diff --git a/docs/examples/ghiper.c b/docs/examples/ghiper.c index fd6041761e..79516ccd82 100644 --- a/docs/examples/ghiper.c +++ b/docs/examples/ghiper.c @@ -258,7 +258,9 @@ static int sock_cb(CURL *e, curl_socket_t s, int what, void *cbp, void *sockp) { struct GlobalInfo *g = (struct GlobalInfo *)cbp; struct SockInfo *fdp = (struct SockInfo *)sockp; - static const char *whatstr[] = { "none", "IN", "OUT", "INOUT", "REMOVE" }; + static const char * const whatstr[] = { + "none", "IN", "OUT", "INOUT", "REMOVE" + }; MSG_OUT("socket callback: s=%d e=%p what=%s ", s, e, whatstr[what]); if(what == CURL_POLL_REMOVE) { @@ -395,8 +397,8 @@ static gboolean fifo_cb(GIOChannel *ch, GIOCondition condition, gpointer data) int init_fifo(void) { + static const char fifo[] = "hiper.fifo"; struct stat st; - const char *fifo = "hiper.fifo"; int socket; if(!lstat(fifo, &st)) { diff --git a/docs/examples/hiperfifo.c b/docs/examples/hiperfifo.c index 96719530cf..cc27799012 100644 --- a/docs/examples/hiperfifo.c +++ b/docs/examples/hiperfifo.c @@ -270,7 +270,9 @@ static int sock_cb(CURL *e, curl_socket_t s, int what, void *cbp, void *sockp) { struct GlobalInfo *g = (struct GlobalInfo *)cbp; struct SockInfo *fdp = (struct SockInfo *)sockp; - const char *whatstr[] = { "none", "IN", "OUT", "INOUT", "REMOVE" }; + static const char * const whatstr[] = { + "none", "IN", "OUT", "INOUT", "REMOVE" + }; fprintf(MSG_OUT, "socket callback: s=%d e=%p what=%s ", s, e, whatstr[what]); if(what == CURL_POLL_REMOVE) { @@ -376,7 +378,7 @@ static void fifo_cb(int fd, short event, void *arg) } /* Create a named pipe and tell libevent to monitor it */ -static const char *fifo = "hiper.fifo"; +static const char fifo[] = "hiper.fifo"; static int init_fifo(struct GlobalInfo *g) { struct stat st; diff --git a/docs/examples/imap-append.c b/docs/examples/imap-append.c index 77cf2bc02a..c530bbb9c8 100644 --- a/docs/examples/imap-append.c +++ b/docs/examples/imap-append.c @@ -40,7 +40,7 @@ #define TO "" #define CC "" -static const char *payload_text = +static const char payload_text[] = "Date: Mon, 29 Nov 2010 21:54:29 +1100\r\n" "To: " TO "\r\n" "From: " FROM "(Example User)\r\n" @@ -111,7 +111,7 @@ int main(void) curl_easy_setopt(curl, CURLOPT_READDATA, &upload_ctx); curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); - filesize = strlen(payload_text); + filesize = sizeof(payload_text) - 1; if(filesize <= LONG_MAX) infilesize = (long)filesize; curl_easy_setopt(curl, CURLOPT_INFILESIZE, infilesize); diff --git a/docs/examples/maxconnects.c b/docs/examples/maxconnects.c index 7ef29828ea..b52f1fcc3f 100644 --- a/docs/examples/maxconnects.c +++ b/docs/examples/maxconnects.c @@ -39,7 +39,7 @@ int main(void) curl = curl_easy_init(); if(curl) { - const char *urls[] = { + static const char * const urls[] = { "https://example.com/", "https://curl.se/", "https://www.example/", diff --git a/docs/examples/postinmemory.c b/docs/examples/postinmemory.c index c4d9abcc11..7f18e8e5f5 100644 --- a/docs/examples/postinmemory.c +++ b/docs/examples/postinmemory.c @@ -61,7 +61,7 @@ int main(void) CURL *curl; CURLcode result; struct MemoryStruct chunk; - static const char *postthis = "Field=1&Field=2&Field=3"; + static const char postthis[] = "Field=1&Field=2&Field=3"; result = curl_global_init(CURL_GLOBAL_ALL); if(result != CURLE_OK) @@ -87,7 +87,7 @@ int main(void) curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postthis); /* if we do not provide POSTFIELDSIZE, libcurl calls strlen() by itself */ - curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)strlen(postthis)); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)sizeof(postthis) - 1); /* Perform the request, result gets the return code */ result = curl_easy_perform(curl); diff --git a/docs/examples/sendrecv.c b/docs/examples/sendrecv.c index 2777ca0a6d..a3539adb3c 100644 --- a/docs/examples/sendrecv.c +++ b/docs/examples/sendrecv.c @@ -77,8 +77,8 @@ int main(void) { CURL *curl; /* Minimalistic http request */ - const char *request = "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n"; - size_t request_len = strlen(request); + static const char request[] = "GET / HTTP/1.0\r\nHost: example.com\r\n\r\n"; + static const size_t request_len = sizeof(request) - 1; CURLcode result = curl_global_init(CURL_GLOBAL_ALL); if(result != CURLE_OK) diff --git a/docs/examples/sepheaders.c b/docs/examples/sepheaders.c index c9fee6c2ba..011eae1aea 100644 --- a/docs/examples/sepheaders.c +++ b/docs/examples/sepheaders.c @@ -53,9 +53,9 @@ int main(void) /* init the curl session */ curl = curl_easy_init(); if(curl) { - static const char *headerfilename = "head.out"; + static const char headerfilename[] = "head.out"; FILE *headerfile; - static const char *bodyfilename = "body.out"; + static const char bodyfilename[] = "body.out"; FILE *bodyfile; /* set URL to get */ diff --git a/docs/examples/sftpuploadresume.c b/docs/examples/sftpuploadresume.c index 153883640b..e5d14a8459 100644 --- a/docs/examples/sftpuploadresume.c +++ b/docs/examples/sftpuploadresume.c @@ -134,8 +134,8 @@ int main(void) curl = curl_easy_init(); if(curl) { - const char *remote = "sftp://user:pass@example.com/path/filename"; - const char *filename = "filename"; + static const char remote[] = "sftp://user:pass@example.com/path/filename"; + static const char filename[] = "filename"; if(!sftpResumeUpload(curl, remote, filename)) { printf("resumed upload using curl %s failed\n", curl_version()); diff --git a/docs/examples/simplepost.c b/docs/examples/simplepost.c index d2540151ce..fb85677c31 100644 --- a/docs/examples/simplepost.c +++ b/docs/examples/simplepost.c @@ -32,7 +32,7 @@ int main(void) { - static const char *postthis = "moo mooo moo moo"; + static const char postthis[] = "moo mooo moo moo"; CURL *curl; @@ -46,7 +46,7 @@ int main(void) curl_easy_setopt(curl, CURLOPT_POSTFIELDS, postthis); /* if we do not provide POSTFIELDSIZE, libcurl calls strlen() by itself */ - curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)strlen(postthis)); + curl_easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)sizeof(postthis) - 1); /* Perform the request, result gets the return code */ result = curl_easy_perform(curl); diff --git a/docs/examples/simplessl.c b/docs/examples/simplessl.c index 24e08c4c71..45db65a05d 100644 --- a/docs/examples/simplessl.c +++ b/docs/examples/simplessl.c @@ -55,9 +55,9 @@ int main(void) FILE *headerfile; const char *pPassphrase = NULL; - static const char *pCertFile = "testcert.pem"; - static const char *pCACertFile = "cacert.pem"; - static const char *pHeaderFile = "dumpit"; + static const char pCertFile[] = "testcert.pem"; + static const char pCACertFile[] = "cacert.pem"; + static const char pHeaderFile[] = "dumpit"; const char *pKeyName; const char *pKeyType; diff --git a/docs/examples/smtp-authzid.c b/docs/examples/smtp-authzid.c index fe91ba5e63..0260452990 100644 --- a/docs/examples/smtp-authzid.c +++ b/docs/examples/smtp-authzid.c @@ -48,7 +48,7 @@ #define SENDER_MAIL "Kurt " SENDER_ADDR #define TO_MAIL "A Receiver " TO_ADDR -static const char *payload_text = +static const char payload_text[] = "Date: Mon, 29 Nov 2010 21:54:29 +1100\r\n" "To: " TO_MAIL "\r\n" "From: " FROM_MAIL "\r\n" diff --git a/docs/examples/smtp-mail.c b/docs/examples/smtp-mail.c index b1590fd3af..618123ab5e 100644 --- a/docs/examples/smtp-mail.c +++ b/docs/examples/smtp-mail.c @@ -45,7 +45,7 @@ #define TO_MAIL "A Receiver " TO_ADDR #define CC_MAIL "John CC Smith " CC_ADDR -static const char *payload_text = +static const char payload_text[] = "Date: Mon, 29 Nov 2010 21:54:29 +1100\r\n" "To: " TO_MAIL "\r\n" "From: " FROM_MAIL "\r\n" diff --git a/docs/examples/smtp-mime.c b/docs/examples/smtp-mime.c index 0ddba4ebb7..4d54532559 100644 --- a/docs/examples/smtp-mime.c +++ b/docs/examples/smtp-mime.c @@ -41,7 +41,7 @@ #define TO "" #define CC "" -static const char *headers_text[] = { +static const char * const headers_text[] = { "Date: Tue, 22 Aug 2017 14:08:43 +0100", "To: " TO, "From: " FROM " (Example User)", @@ -82,7 +82,7 @@ int main(void) curl_mime *mime; curl_mime *alt; curl_mimepart *part; - const char **cpp; + const char * const *cpp; /* This is the URL for your mailserver */ curl_easy_setopt(curl, CURLOPT_URL, "smtp://mail.example.com"); diff --git a/docs/examples/smtp-multi.c b/docs/examples/smtp-multi.c index 86545a1ef3..9d76a57fe7 100644 --- a/docs/examples/smtp-multi.c +++ b/docs/examples/smtp-multi.c @@ -38,7 +38,7 @@ #define TO_MAIL "" #define CC_MAIL "" -static const char *payload_text = +static const char payload_text[] = "Date: Mon, 29 Nov 2010 21:54:29 +1100\r\n" "To: " TO_MAIL "\r\n" "From: " FROM_MAIL "\r\n" diff --git a/docs/examples/smtp-ssl.c b/docs/examples/smtp-ssl.c index 9cac9ecd52..172f66b8da 100644 --- a/docs/examples/smtp-ssl.c +++ b/docs/examples/smtp-ssl.c @@ -42,7 +42,7 @@ #define TO_MAIL "" #define CC_MAIL "" -static const char *payload_text = +static const char payload_text[] = "Date: Mon, 29 Nov 2010 21:54:29 +1100\r\n" "To: " TO_MAIL "\r\n" "From: " FROM_MAIL "\r\n" diff --git a/docs/examples/smtp-tls.c b/docs/examples/smtp-tls.c index da452318a6..c3c992717b 100644 --- a/docs/examples/smtp-tls.c +++ b/docs/examples/smtp-tls.c @@ -42,7 +42,7 @@ #define TO_MAIL "" #define CC_MAIL "" -static const char *payload_text = +static const char payload_text[] = "Date: Mon, 29 Nov 2010 21:54:29 +1100\r\n" "To: " TO_MAIL "\r\n" "From: " FROM_MAIL "\r\n" diff --git a/docs/examples/synctime.c b/docs/examples/synctime.c index 2c7501d4db..8e9adf1f3f 100644 --- a/docs/examples/synctime.c +++ b/docs/examples/synctime.c @@ -99,10 +99,10 @@ static int AutoSyncTime; static SYSTEMTIME SYSTime; static SYSTEMTIME LOCALTime; -static const char *DayStr[] = { +static const char * const DayStr[] = { "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat" }; -static const char *MthStr[] = { +static const char * const MthStr[] = { "Jan", "Feb", "Mar", "Apr", "May", "Jun", "Jul", "Aug", "Sep", "Oct", "Nov", "Dec" }; diff --git a/docs/examples/url2file.c b/docs/examples/url2file.c index ce8805a40e..1216575638 100644 --- a/docs/examples/url2file.c +++ b/docs/examples/url2file.c @@ -44,7 +44,7 @@ static size_t write_cb(char *ptr, size_t size, size_t nmemb, void *stream) int main(int argc, const char *argv[]) { - static const char *pagefilename = "page.out"; + static const char pagefilename[] = "page.out"; CURLcode result; CURL *curl; diff --git a/docs/examples/websocket-updown.c b/docs/examples/websocket-updown.c index 85a7e74ea3..495c4b7166 100644 --- a/docs/examples/websocket-updown.c +++ b/docs/examples/websocket-updown.c @@ -88,7 +88,7 @@ int main(int argc, const char *argv[]) { CURL *curl; struct read_ctx rctx; - const char *payload = "Hello, friend!"; + static const char payload[] = "Hello, friend!"; CURLcode result = curl_global_init(CURL_GLOBAL_ALL); if(result != CURLE_OK) @@ -108,7 +108,7 @@ int main(int argc, const char *argv[]) curl_easy_setopt(curl, CURLOPT_READFUNCTION, read_cb); /* tell curl that we want to send the payload */ rctx.curl = curl; - rctx.blen = strlen(payload); + rctx.blen = sizeof(payload) - 1; memcpy(rctx.buf, payload, rctx.blen); curl_easy_setopt(curl, CURLOPT_READDATA, &rctx); curl_easy_setopt(curl, CURLOPT_UPLOAD, 1L); diff --git a/lib/cf-h1-proxy.c b/lib/cf-h1-proxy.c index f1e5c7a42a..b425249588 100644 --- a/lib/cf-h1-proxy.c +++ b/lib/cf-h1-proxy.c @@ -329,7 +329,7 @@ static CURLcode on_resp_header_udp(struct Curl_cfilter *cf, k->httpcode); } else { - const char *p = header + strlen("Content-Length:"); + const char *p = header + CURL_CSTRLEN("Content-Length:"); if(curlx_str_numblanks(&p, &ts->cl)) { failf(data, "Unsupported Content-Length value"); return CURLE_WEIRD_SERVER_REPLY; @@ -419,7 +419,7 @@ static CURLcode on_resp_header(struct Curl_cfilter *cf, k->httpcode); } else { - const char *p = header + strlen("Content-Length:"); + const char *p = header + CURL_CSTRLEN("Content-Length:"); if(curlx_str_numblanks(&p, &ts->cl)) { failf(data, "Unsupported Content-Length value"); return CURLE_WEIRD_SERVER_REPLY; diff --git a/lib/cf-h2-proxy.c b/lib/cf-h2-proxy.c index be303ffd3e..86e04fc0ec 100644 --- a/lib/cf-h2-proxy.c +++ b/lib/cf-h2-proxy.c @@ -574,7 +574,7 @@ static int proxy_h2_on_header(nghttp2_session *session, return 0; } - if(namelen == sizeof(HTTP_PSEUDO_STATUS) - 1 && + if(namelen == CURL_CSTRLEN(HTTP_PSEUDO_STATUS) && !memcmp(HTTP_PSEUDO_STATUS, name, namelen)) { int http_status; struct http_resp *resp; diff --git a/lib/curl_setup.h b/lib/curl_setup.h index a91b912f3e..e6d5b8f694 100644 --- a/lib/curl_setup.h +++ b/lib/curl_setup.h @@ -1291,10 +1291,14 @@ typedef unsigned int curl_bit; #define CURLMAX(x, y) ((x) > (y) ? (x) : (y)) #define CURLMIN(x, y) ((x) < (y) ? (x) : (y)) +/* Convenience macro to provide the length of a string literal size without + the null-terminator. Equivalent to strlen() for constant strings. */ +#define CURL_CSTRLEN(x) (sizeof(x) - 1) + /* A convenience macro to provide both the string literal and the length of the string literal in one go, useful for functions that take "string,len" as their argument */ -#define STRCONST(x) x, sizeof(x) - 1 +#define STRCONST(x) x, CURL_CSTRLEN(x) #define CURL_ARRAYSIZE(A) (sizeof(A) / sizeof((A)[0])) diff --git a/lib/dict.c b/lib/dict.c index db25d5a721..2a0053e934 100644 --- a/lib/dict.c +++ b/lib/dict.c @@ -153,9 +153,9 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done) if(result) return result; - if(curl_strnequal(path, DICT_MATCH, sizeof(DICT_MATCH) - 1) || - curl_strnequal(path, DICT_MATCH2, sizeof(DICT_MATCH2) - 1) || - curl_strnequal(path, DICT_MATCH3, sizeof(DICT_MATCH3) - 1)) { + if(curl_strnequal(path, DICT_MATCH, CURL_CSTRLEN(DICT_MATCH)) || + curl_strnequal(path, DICT_MATCH2, CURL_CSTRLEN(DICT_MATCH2)) || + curl_strnequal(path, DICT_MATCH3, CURL_CSTRLEN(DICT_MATCH3))) { word = strchr(path, ':'); if(word) { @@ -200,9 +200,9 @@ static CURLcode dict_do(struct Curl_easy *data, bool *done) } Curl_xfer_setup_recv(data, FIRSTSOCKET, -1); } - else if(curl_strnequal(path, DICT_DEFINE, sizeof(DICT_DEFINE) - 1) || - curl_strnequal(path, DICT_DEFINE2, sizeof(DICT_DEFINE2) - 1) || - curl_strnequal(path, DICT_DEFINE3, sizeof(DICT_DEFINE3) - 1)) { + else if(curl_strnequal(path, DICT_DEFINE, CURL_CSTRLEN(DICT_DEFINE)) || + curl_strnequal(path, DICT_DEFINE2, CURL_CSTRLEN(DICT_DEFINE2)) || + curl_strnequal(path, DICT_DEFINE3, CURL_CSTRLEN(DICT_DEFINE3))) { word = strchr(path, ':'); if(word) { diff --git a/lib/http.c b/lib/http.c index c8c0084233..4feb930069 100644 --- a/lib/http.c +++ b/lib/http.c @@ -5026,7 +5026,7 @@ CURLcode Curl_http_req_to_h2(struct dynhds *h2_headers, if(e->namelen == 2 && curl_strequal("TE", e->name)) { if(http_TE_has_token(e->value, "trailers")) result = Curl_dynhds_add(h2_headers, e->name, e->namelen, - "trailers", sizeof("trailers") - 1); + "trailers", CURL_CSTRLEN("trailers")); } else if(h2_permissible_field(e)) { result = Curl_dynhds_add(h2_headers, e->name, e->namelen, diff --git a/lib/http2.c b/lib/http2.c index a63fc4a59c..8d4a93cb58 100644 --- a/lib/http2.c +++ b/lib/http2.c @@ -1427,7 +1427,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, if(frame->hd.type == NGHTTP2_PUSH_PROMISE) { char *h; - if((namelen == (sizeof(HTTP_PSEUDO_AUTHORITY) - 1)) && + if((namelen == CURL_CSTRLEN(HTTP_PSEUDO_AUTHORITY)) && !strncmp(HTTP_PSEUDO_AUTHORITY, (const char *)name, namelen)) { /* pseudo headers are lower case */ int rc = 0; @@ -1503,7 +1503,7 @@ static int on_header(nghttp2_session *session, const nghttp2_frame *frame, return 0; } - if(namelen == sizeof(HTTP_PSEUDO_STATUS) - 1 && + if(namelen == CURL_CSTRLEN(HTTP_PSEUDO_STATUS) && !memcmp(HTTP_PSEUDO_STATUS, name, namelen)) { /* nghttp2 guarantees :status is received first and only once. */ char buffer[32]; diff --git a/lib/http_aws_sigv4.c b/lib/http_aws_sigv4.c index d4ad7cc5f0..bff66a9582 100644 --- a/lib/http_aws_sigv4.c +++ b/lib/http_aws_sigv4.c @@ -623,7 +623,7 @@ static CURLcode calc_s3_payload_hash(struct Curl_easy *data, } else { /* Fall back to s3's UNSIGNED-PAYLOAD */ - size_t len = sizeof(S3_UNSIGNED_PAYLOAD) - 1; + size_t len = CURL_CSTRLEN(S3_UNSIGNED_PAYLOAD); DEBUGASSERT(len < SHA256_HEX_LENGTH); /* 16 < 65 */ memcpy(sha_hex, S3_UNSIGNED_PAYLOAD, len); sha_hex[len] = 0; @@ -1143,7 +1143,7 @@ static CURLcode sign_and_set_auth_headers(struct Curl_easy *data, goto fail; /* provider 0 uppercase */ - Curl_strntoupper(&auth_headers[sizeof("Authorization: ") - 1], + Curl_strntoupper(&auth_headers[CURL_CSTRLEN("Authorization: ")], curlx_str(provider0), curlx_strlen(provider0)); curlx_free(data->req.hd_auth); diff --git a/lib/http_digest.c b/lib/http_digest.c index 31a9db35a8..90350a1d1e 100644 --- a/lib/http_digest.c +++ b/lib/http_digest.c @@ -54,7 +54,7 @@ CURLcode Curl_input_digest(struct Curl_easy *data, if(!checkprefix("Digest", header) || !ISBLANK(header[6])) return CURLE_AUTH_ERROR; - header += strlen("Digest"); + header += CURL_CSTRLEN("Digest"); curlx_str_passblanks(&header); return Curl_auth_decode_digest_http_message(header, digest); diff --git a/lib/http_negotiate.c b/lib/http_negotiate.c index 891369b5bc..7aaa6878d1 100644 --- a/lib/http_negotiate.c +++ b/lib/http_negotiate.c @@ -83,7 +83,7 @@ CURLcode Curl_input_negotiate(struct Curl_easy *data, struct connectdata *conn, return CURLE_OUT_OF_MEMORY; /* Obtain the input token, if any */ - header += strlen("Negotiate"); + header += CURL_CSTRLEN("Negotiate"); curlx_str_passblanks(&header); len = strlen(header); diff --git a/lib/http_ntlm.c b/lib/http_ntlm.c index dc9911fdac..b0a73a6c8a 100644 --- a/lib/http_ntlm.c +++ b/lib/http_ntlm.c @@ -65,7 +65,7 @@ CURLcode Curl_input_ntlm(struct Curl_easy *data, if(!ntlm) return CURLE_OUT_OF_MEMORY; - header += strlen("NTLM"); + header += CURL_CSTRLEN("NTLM"); curlx_str_passblanks(&header); if(*header) { unsigned char *hdr; diff --git a/lib/http_proxy.c b/lib/http_proxy.c index aa20a52ebe..c658b82478 100644 --- a/lib/http_proxy.c +++ b/lib/http_proxy.c @@ -215,7 +215,7 @@ static CURLcode http_proxy_create_CONNECT(struct httpreq **preq, goto out; } - result = Curl_http_req_make(&req, "CONNECT", sizeof("CONNECT") - 1, + result = Curl_http_req_make(&req, "CONNECT", CURL_CSTRLEN("CONNECT"), NULL, 0, authority, strlen(authority), NULL, 0); if(result) @@ -340,7 +340,7 @@ static CURLcode http_proxy_create_CONNECTUDP(struct httpreq **preq, } if(ver == PROXY_HTTP_V1) { - result = Curl_http_req_make(&req, "GET", sizeof("GET")-1, + result = Curl_http_req_make(&req, "GET", CURL_CSTRLEN("GET"), proxy_scheme, strlen(proxy_scheme), authority, strlen(authority), path, strlen(path)); @@ -348,7 +348,7 @@ static CURLcode http_proxy_create_CONNECTUDP(struct httpreq **preq, goto out; } else if(ver == PROXY_HTTP_V2 || ver == PROXY_HTTP_V3) { - result = Curl_http_req_make(&req, "CONNECT", sizeof("CONNECT") - 1, + result = Curl_http_req_make(&req, "CONNECT", CURL_CSTRLEN("CONNECT"), proxy_scheme, strlen(proxy_scheme), authority, strlen(authority), path, strlen(path)); diff --git a/lib/imap.c b/lib/imap.c index 6a48f85152..8f0c297715 100644 --- a/lib/imap.c +++ b/lib/imap.c @@ -1357,7 +1357,7 @@ static CURLcode imap_state_select_resp(struct Curl_easy *data, size_t len = curlx_dyn_len(&imapc->pp.recvbuf); if((len >= 18) && checkprefix("OK [UIDVALIDITY ", &line[2])) { curl_off_t value; - const char *p = &line[2] + strlen("OK [UIDVALIDITY "); + const char *p = &line[2] + CURL_CSTRLEN("OK [UIDVALIDITY "); if(!curlx_str_number(&p, &value, UINT_MAX)) { imapc->mb_uidvalidity = (unsigned int)value; imapc->mb_uidvalidity_set = TRUE; diff --git a/lib/ldap.c b/lib/ldap.c index dac472d4c9..a7c1fe8c83 100644 --- a/lib/ldap.c +++ b/lib/ldap.c @@ -976,9 +976,9 @@ void Curl_ldap_version(char *buf, size_t bufsz) curl_msnprintf(buf, bufsz, "WinLDAP"); #else #ifdef LDAP_OPT_X_TLS_PASSPHRASE - static const char *flavor = "/Apple"; + static const char flavor[] = "/Apple"; #else - static const char *flavor = ""; + static const char flavor[] = ""; #endif LDAPAPIInfo api; api.ldapai_info_version = LDAP_API_INFO_VERSION; diff --git a/lib/mqtt.c b/lib/mqtt.c index a9cdf21498..0858fd65f6 100644 --- a/lib/mqtt.c +++ b/lib/mqtt.c @@ -276,7 +276,7 @@ static CURLcode mqtt_connect(struct Curl_easy *data) size_t start_user = 0; size_t start_pwd = 0; char client_id[MQTT_CLIENTID_LEN + 1] = "curl"; - const size_t clen = strlen("curl"); + const size_t clen = CURL_CSTRLEN("curl"); char *packet = NULL; /* extracting username from request */ @@ -627,7 +627,7 @@ static bool mqtt_decode_len(size_t *lenp, const unsigned char *buf, } #if defined(DEBUGBUILD) && defined(CURLVERBOSE) -static const char *statenames[] = { +static const char * const statenames[] = { "MQTT_FIRST", "MQTT_REMAINING_LENGTH", "MQTT_CONNACK", diff --git a/lib/progress.c b/lib/progress.c index 3c0f3d57d7..b6322461d5 100644 --- a/lib/progress.c +++ b/lib/progress.c @@ -91,7 +91,7 @@ UNITTEST char *max6out(curl_off_t bytes, char *max6, size_t mlen) if(bytes < 100000) curl_msnprintf(max6, mlen, "%6" CURL_FORMAT_CURL_OFF_T, bytes); else { - const char unit[] = { 'k', 'M', 'G', 'T', 'P', 'E', 0 }; + static const char unit[] = { 'k', 'M', 'G', 'T', 'P', 'E', 0 }; int k = 0; curl_off_t nbytes; curl_off_t rest; diff --git a/lib/smb.c b/lib/smb.c index 2d1a859aa1..4299190ff5 100644 --- a/lib/smb.c +++ b/lib/smb.c @@ -654,9 +654,10 @@ static CURLcode smb_send_negotiate(struct Curl_easy *data, struct smb_conn *smbc, struct smb_request *req) { - const char *msg = "\x00\x0c\x00\x02NT LM 0.12"; + static const char msg[] = "\x00\x0c\x00\x02NT LM 0.12"; - return smb_send_message(data, smbc, req, SMB_COM_NEGOTIATE, msg, 15); + return smb_send_message(data, smbc, req, SMB_COM_NEGOTIATE, msg, + sizeof(msg)); } static CURLcode smb_send_setup(struct Curl_easy *data) @@ -678,7 +679,7 @@ static CURLcode smb_send_setup(struct Curl_easy *data) byte_count = sizeof(lm) + sizeof(nt) + strlen(smbc->user) + strlen(smbc->domain) + - strlen(CURL_OS) + strlen(CLIENTNAME) + 4; /* 4 null chars */ + CURL_CSTRLEN(CURL_OS) + CURL_CSTRLEN(CLIENTNAME) + 4; /* 4 null chars */ if(byte_count > sizeof(msg.bytes)) return CURLE_FILESIZE_EXCEEDED; @@ -724,7 +725,7 @@ static CURLcode smb_send_tree_connect(struct Curl_easy *data, char *p = msg.bytes; const size_t byte_count = strlen(conn->origin->hostname) + strlen(smbc->share) + - strlen(SERVICENAME) + 5; /* 2 nulls and 3 backslashes */ + CURL_CSTRLEN(SERVICENAME) + 5; /* 2 nulls and 3 backslashes */ if(byte_count > sizeof(msg.bytes)) return CURLE_FILESIZE_EXCEEDED; diff --git a/lib/tftp.c b/lib/tftp.c index d5c85a3100..c101edebed 100644 --- a/lib/tftp.c +++ b/lib/tftp.c @@ -278,7 +278,7 @@ static CURLcode tftp_parse_option_ack(struct tftp_conn *state, infof(data, "got option=(%s) value=(%s)", option, value); - if((strlen(TFTP_OPTION_BLKSIZE) == olen) && + if((CURL_CSTRLEN(TFTP_OPTION_BLKSIZE) == olen) && checkprefix(TFTP_OPTION_BLKSIZE, option)) { curl_off_t blksize; if(curlx_str_number(&value, &blksize, TFTP_BLKSIZE_MAX)) { @@ -308,7 +308,7 @@ static CURLcode tftp_parse_option_ack(struct tftp_conn *state, infof(data, "blksize parsed from OACK (%u) requested (%u)", state->blksize, state->requested_blksize); } - else if((strlen(TFTP_OPTION_TSIZE) == olen) && + else if((CURL_CSTRLEN(TFTP_OPTION_TSIZE) == olen) && checkprefix(TFTP_OPTION_TSIZE, option)) { curl_off_t tsize = 0; /* tsize should be ignored on upload: Who cares about the size of the diff --git a/lib/vquic/cf-quiche.c b/lib/vquic/cf-quiche.c index c23b810254..bfc68adf14 100644 --- a/lib/vquic/cf-quiche.c +++ b/lib/vquic/cf-quiche.c @@ -1298,9 +1298,8 @@ static CURLcode cf_quiche_ctx_open(struct Curl_cfilter *cf, 10 * QUIC_MAX_STREAMS * H3_STREAM_WINDOW_SIZE); quiche_config_set_max_stream_window(ctx->cfg, 10 * H3_STREAM_WINDOW_SIZE); quiche_config_set_application_protos(ctx->cfg, - (uint8_t *)CURL_UNCONST(QUICHE_H3_APPLICATION_PROTOCOL), - sizeof(QUICHE_H3_APPLICATION_PROTOCOL) - - 1); + (uint8_t *)CURL_UNCONST(QUICHE_H3_APPLICATION_PROTOCOL), + CURL_CSTRLEN(QUICHE_H3_APPLICATION_PROTOCOL)); result = Curl_vquic_tls_init(&ctx->tls, cf, data, &ctx->ssl_peer, &ALPN_SPEC_H3, NULL, NULL, cf, NULL); @@ -1351,7 +1350,7 @@ static CURLcode cf_quiche_ctx_open(struct Curl_cfilter *cf, unsigned alpn_len, offset = 0; /* Replace each ALPN length prefix by a comma. */ - while(offset < sizeof(alpn_protocols) - 1) { + while(offset < CURL_CSTRLEN(alpn_protocols)) { alpn_len = alpn_protocols[offset]; alpn_protocols[offset] = ','; offset += 1 + alpn_len; diff --git a/lib/vssh/libssh2.c b/lib/vssh/libssh2.c index effcc9beaf..940c678358 100644 --- a/lib/vssh/libssh2.c +++ b/lib/vssh/libssh2.c @@ -1768,7 +1768,7 @@ static CURLcode ssh_state_sftp_realpath(struct Curl_easy *data, return CURLE_FAILED_INIT; rc = libssh2_sftp_symlink_ex(sshc->sftp_session, ".", - curlx_uztoui(strlen(".")), + curlx_uztoui(CURL_CSTRLEN(".")), sshp->readdir_filename, CURL_PATH_MAX, LIBSSH2_SFTP_REALPATH); if(rc == LIBSSH2_ERROR_EAGAIN) diff --git a/lib/vtls/cipher_suite.c b/lib/vtls/cipher_suite.c index 197055fc0d..2c6a0c02d0 100644 --- a/lib/vtls/cipher_suite.c +++ b/lib/vtls/cipher_suite.c @@ -48,7 +48,7 @@ /* Text for cipher suite parts (max 64 entries), keep indexes below in sync with this! */ -static const char *cs_txt = +static const char cs_txt[] = "\0" "TLS" "\0" "WITH" "\0" diff --git a/lib/vtls/gtls.c b/lib/vtls/gtls.c index 423179172f..92607b1135 100644 --- a/lib/vtls/gtls.c +++ b/lib/vtls/gtls.c @@ -591,7 +591,7 @@ static struct gtls_shared_creds *gtls_get_cached_creds(struct Curl_cfilter *cf, if(data->multi) { shared_creds = Curl_hash_pick(&data->multi->proto_hash, CURL_UNCONST(MPROTO_GTLS_X509_KEY), - sizeof(MPROTO_GTLS_X509_KEY) - 1); + CURL_CSTRLEN(MPROTO_GTLS_X509_KEY)); if(shared_creds && shared_creds->creds && !gtls_shared_creds_expired(data, shared_creds) && !gtls_shared_creds_different(cf, shared_creds)) { @@ -604,7 +604,7 @@ static struct gtls_shared_creds *gtls_get_cached_creds(struct Curl_cfilter *cf, static void gtls_shared_creds_hash_free(void *key, size_t key_len, void *p) { struct gtls_shared_creds *sc = p; - DEBUGASSERT(key_len == (sizeof(MPROTO_GTLS_X509_KEY) - 1)); + DEBUGASSERT(key_len == CURL_CSTRLEN(MPROTO_GTLS_X509_KEY)); DEBUGASSERT(!memcmp(MPROTO_GTLS_X509_KEY, key, key_len)); (void)key; (void)key_len; @@ -635,7 +635,7 @@ static void gtls_set_cached_creds(struct Curl_cfilter *cf, if(!Curl_hash_add2(&data->multi->proto_hash, CURL_UNCONST(MPROTO_GTLS_X509_KEY), - sizeof(MPROTO_GTLS_X509_KEY) - 1, + CURL_CSTRLEN(MPROTO_GTLS_X509_KEY), sc, gtls_shared_creds_hash_free)) { Curl_gtls_shared_creds_free(&sc); /* down reference again */ return; diff --git a/lib/vtls/keylog.h b/lib/vtls/keylog.h index b09fcc6f4d..f95dfeae2d 100644 --- a/lib/vtls/keylog.h +++ b/lib/vtls/keylog.h @@ -25,7 +25,7 @@ ***************************************************************************/ #include "curl_setup.h" -#define KEYLOG_LABEL_MAXLEN (sizeof("CLIENT_HANDSHAKE_TRAFFIC_SECRET") - 1) +#define KEYLOG_LABEL_MAXLEN CURL_CSTRLEN("CLIENT_HANDSHAKE_TRAFFIC_SECRET") #define CLIENT_RANDOM_SIZE 32 diff --git a/lib/vtls/openssl.c b/lib/vtls/openssl.c index 9f576a9d52..12903038f1 100644 --- a/lib/vtls/openssl.c +++ b/lib/vtls/openssl.c @@ -248,7 +248,7 @@ static CURLcode X509V3_ext(struct Curl_easy *data, if(asn1_object_dump(obj, namebuf, sizeof(namebuf))) /* make sure the name is null-terminated */ - namebuf[sizeof(namebuf) - 1] = 0; + namebuf[CURL_CSTRLEN(namebuf)] = 0; if(!X509V3_EXT_print(bio_out, ext, 0, 0)) ASN1_STRING_print(bio_out, @@ -1176,7 +1176,7 @@ static int engineload(struct Curl_easy *data, } if(data->state.engine) { - const char *cmd_name = "LOAD_CERT_CTRL"; + static const char cmd_name[] = "LOAD_CERT_CTRL"; struct { const char *cert_id; X509 *cert; @@ -2965,7 +2965,7 @@ static CURLcode ossl_windows_load_anchors(struct Curl_cfilter *cf, https://stackoverflow.com/questions/9507184/ https://github.com/d3x0r/SACK/blob/ff15424d3c581b86d40f818532e5a400c516d39d/src/netlib/ssl_layer.c#L1410 https://datatracker.ietf.org/doc/html/rfc5280 */ - const char *win_stores[] = { + static const char * const win_stores[] = { "ROOT", /* Trusted Root Certification Authorities */ "CA" /* Intermediate Certification Authorities */ }; @@ -3180,7 +3180,7 @@ struct ossl_x509_share { static void oss_x509_share_free(void *key, size_t key_len, void *p) { struct ossl_x509_share *share = p; - DEBUGASSERT(key_len == (sizeof(MPROTO_OSSL_X509_KEY) - 1)); + DEBUGASSERT(key_len == CURL_CSTRLEN(MPROTO_OSSL_X509_KEY)); DEBUGASSERT(!memcmp(MPROTO_OSSL_X509_KEY, key, key_len)); (void)key; (void)key_len; @@ -3231,7 +3231,7 @@ static X509_STORE *ossl_get_cached_x509_store(struct Curl_cfilter *cf, *pempty = TRUE; share = multi ? Curl_hash_pick(&multi->proto_hash, CURL_UNCONST(MPROTO_OSSL_X509_KEY), - sizeof(MPROTO_OSSL_X509_KEY) - 1) : NULL; + CURL_CSTRLEN(MPROTO_OSSL_X509_KEY)) : NULL; if(share && share->store && !ossl_cached_x509_store_expired(data, share) && !ossl_cached_x509_store_different(cf, data, share)) { @@ -3256,7 +3256,7 @@ static void ossl_set_cached_x509_store(struct Curl_cfilter *cf, return; share = Curl_hash_pick(&multi->proto_hash, CURL_UNCONST(MPROTO_OSSL_X509_KEY), - sizeof(MPROTO_OSSL_X509_KEY) - 1); + CURL_CSTRLEN(MPROTO_OSSL_X509_KEY)); if(!share) { share = curlx_calloc(1, sizeof(*share)); @@ -3264,7 +3264,7 @@ static void ossl_set_cached_x509_store(struct Curl_cfilter *cf, return; if(!Curl_hash_add2(&multi->proto_hash, CURL_UNCONST(MPROTO_OSSL_X509_KEY), - sizeof(MPROTO_OSSL_X509_KEY) - 1, + CURL_CSTRLEN(MPROTO_OSSL_X509_KEY), share, oss_x509_share_free)) { curlx_free(share); return; @@ -5283,7 +5283,7 @@ static CURLcode ossl_get_channel_binding(struct Curl_easy *data, unsigned int length; unsigned char buf[EVP_MAX_MD_SIZE]; - const char prefix[] = "tls-server-end-point:"; + static const char prefix[] = "tls-server-end-point:"; struct connectdata *conn = data->conn; struct Curl_cfilter *cf = conn->cfilter[sockindex]; struct ossl_ctx *octx = NULL; @@ -5405,7 +5405,7 @@ static CURLcode ossl_get_channel_binding(struct Curl_easy *data, } /* Append "tls-server-end-point:" */ - result = curlx_dyn_addn(binding, prefix, sizeof(prefix) - 1); + result = curlx_dyn_addn(binding, prefix, CURL_CSTRLEN(prefix)); if(result) goto out; @@ -5423,9 +5423,9 @@ size_t Curl_ossl_version(char *buffer, size_t size) char *p; size_t count; const char *ver = OpenSSL_version(OPENSSL_VERSION); - const char expected[] = OSSL_PACKAGE " "; /* ie "LibreSSL " */ - if(curl_strnequal(ver, expected, sizeof(expected) - 1)) { - ver += sizeof(expected) - 1; + static const char expected[] = OSSL_PACKAGE " "; /* ie "LibreSSL " */ + if(curl_strnequal(ver, expected, CURL_CSTRLEN(expected))) { + ver += CURL_CSTRLEN(expected); } count = curl_msnprintf(buffer, size, "%s/%s", OSSL_PACKAGE, ver); for(p = buffer; *p; ++p) { diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index 17c1c8d195..f55784c624 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -291,9 +291,9 @@ static CURLcode set_ssl_ciphers(SCHANNEL_CRED *schannel_cred, char *ciphers, if(alg) algIds[algCount++] = (ALG_ID)alg; else if(!strncmp(startCur, "USE_STRONG_CRYPTO", - sizeof("USE_STRONG_CRYPTO") - 1) || + CURL_CSTRLEN("USE_STRONG_CRYPTO")) || !strncmp(startCur, "SCH_USE_STRONG_CRYPTO", - sizeof("SCH_USE_STRONG_CRYPTO") - 1)) + CURL_CSTRLEN("SCH_USE_STRONG_CRYPTO"))) schannel_cred->dwFlags |= SCH_USE_STRONG_CRYPTO; else return CURLE_SSL_CIPHER; @@ -2736,7 +2736,7 @@ HCERTSTORE Curl_schannel_get_cached_cert_store(struct Curl_cfilter *cf, share = Curl_hash_pick(&multi->proto_hash, CURL_UNCONST(MPROTO_SCHANNEL_CERT_SHARE_KEY), - sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY) - 1); + CURL_CSTRLEN(MPROTO_SCHANNEL_CERT_SHARE_KEY)); if(!share || !share->cert_store) { return NULL; } @@ -2785,7 +2785,7 @@ HCERTSTORE Curl_schannel_get_cached_cert_store(struct Curl_cfilter *cf, static void schannel_cert_share_free(void *key, size_t key_len, void *p) { struct schannel_cert_share *share = p; - DEBUGASSERT(key_len == (sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY) - 1)); + DEBUGASSERT(key_len == CURL_CSTRLEN(MPROTO_SCHANNEL_CERT_SHARE_KEY)); DEBUGASSERT(!memcmp(MPROTO_SCHANNEL_CERT_SHARE_KEY, key, key_len)); (void)key; (void)key_len; @@ -2828,7 +2828,7 @@ bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf, share = Curl_hash_pick(&multi->proto_hash, CURL_UNCONST(MPROTO_SCHANNEL_CERT_SHARE_KEY), - sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY) - 1); + CURL_CSTRLEN(MPROTO_SCHANNEL_CERT_SHARE_KEY)); if(!share) { share = curlx_calloc(1, sizeof(*share)); if(!share) { @@ -2837,7 +2837,7 @@ bool Curl_schannel_set_cached_cert_store(struct Curl_cfilter *cf, } if(!Curl_hash_add2(&multi->proto_hash, CURL_UNCONST(MPROTO_SCHANNEL_CERT_SHARE_KEY), - sizeof(MPROTO_SCHANNEL_CERT_SHARE_KEY) - 1, + CURL_CSTRLEN(MPROTO_SCHANNEL_CERT_SHARE_KEY), share, schannel_cert_share_free)) { curlx_free(share); curlx_free(CAfile); diff --git a/lib/vtls/schannel_verify.c b/lib/vtls/schannel_verify.c index e5fe2249a6..6e55c9b839 100644 --- a/lib/vtls/schannel_verify.c +++ b/lib/vtls/schannel_verify.c @@ -119,8 +119,8 @@ static CURLcode add_certs_data_to_store(HCERTSTORE trust_store, const char *ca_file_text, struct Curl_easy *data) { - const size_t begin_cert_len = strlen(BEGIN_CERT); - const size_t end_cert_len = strlen(END_CERT); + const size_t begin_cert_len = CURL_CSTRLEN(BEGIN_CERT); + const size_t end_cert_len = CURL_CSTRLEN(END_CERT); CURLcode result = CURLE_OK; int num_certs = 0; bool more_certs = 1; diff --git a/lib/vtls/vtls.c b/lib/vtls/vtls.c index 2da004adba..952c5e5e71 100644 --- a/lib/vtls/vtls.c +++ b/lib/vtls/vtls.c @@ -483,8 +483,8 @@ CURLcode Curl_pin_peer_pubkey(struct Curl_easy *data, pinned_hash = pinnedpubkey; while(pinned_hash && - !strncmp(pinned_hash, "sha256//", (sizeof("sha256//") - 1))) { - pinned_hash = pinned_hash + (sizeof("sha256//") - 1); + !strncmp(pinned_hash, "sha256//", CURL_CSTRLEN("sha256//"))) { + pinned_hash = pinned_hash + CURL_CSTRLEN("sha256//"); end_pos = strchr(pinned_hash, ';'); pinned_hash_len = end_pos ? (size_t)(end_pos - pinned_hash) : strlen(pinned_hash); diff --git a/lib/vtls/wolfssl.c b/lib/vtls/wolfssl.c index e6ee960117..9fe0dc1c88 100644 --- a/lib/vtls/wolfssl.c +++ b/lib/vtls/wolfssl.c @@ -686,7 +686,7 @@ struct wssl_x509_share { static void wssl_x509_share_free(void *key, size_t key_len, void *p) { struct wssl_x509_share *share = p; - DEBUGASSERT(key_len == (sizeof(MPROTO_WSSL_X509_KEY) - 1)); + DEBUGASSERT(key_len == CURL_CSTRLEN(MPROTO_WSSL_X509_KEY)); DEBUGASSERT(!memcmp(MPROTO_WSSL_X509_KEY, key, key_len)); (void)key; (void)key_len; @@ -730,7 +730,7 @@ static WOLFSSL_X509_STORE *wssl_get_cached_x509_store(struct Curl_cfilter *cf, DEBUGASSERT(multi); share = multi ? Curl_hash_pick(&multi->proto_hash, CURL_UNCONST(MPROTO_WSSL_X509_KEY), - sizeof(MPROTO_WSSL_X509_KEY) - 1) : NULL; + CURL_CSTRLEN(MPROTO_WSSL_X509_KEY)) : NULL; if(share && share->store && !wssl_cached_x509_store_expired(data, share) && !wssl_cached_x509_store_different(cf, share)) { @@ -753,7 +753,7 @@ static void wssl_set_cached_x509_store(struct Curl_cfilter *cf, return; share = Curl_hash_pick(&multi->proto_hash, CURL_UNCONST(MPROTO_WSSL_X509_KEY), - sizeof(MPROTO_WSSL_X509_KEY) - 1); + CURL_CSTRLEN(MPROTO_WSSL_X509_KEY)); if(!share) { share = curlx_calloc(1, sizeof(*share)); @@ -761,7 +761,7 @@ static void wssl_set_cached_x509_store(struct Curl_cfilter *cf, return; if(!Curl_hash_add2(&multi->proto_hash, CURL_UNCONST(MPROTO_WSSL_X509_KEY), - sizeof(MPROTO_WSSL_X509_KEY) - 1, + CURL_CSTRLEN(MPROTO_WSSL_X509_KEY), share, wssl_x509_share_free)) { curlx_free(share); return; diff --git a/scripts/schemetable.c b/scripts/schemetable.c index 8127ecd2a1..67f6b81b14 100644 --- a/scripts/schemetable.c +++ b/scripts/schemetable.c @@ -29,7 +29,7 @@ * function in url.c. */ -static const char *scheme[] = { +static const char * const scheme[] = { "dict", "file", "ftp", diff --git a/src/curlinfo.c b/src/curlinfo.c index 36eabeb78f..8b4659200f 100644 --- a/src/curlinfo.c +++ b/src/curlinfo.c @@ -43,7 +43,7 @@ #include /* for OPENSSL_NO_OCSP */ #endif -static const char *disabled[] = { +static const char * const disabled[] = { "bindlocal: " #ifdef CURL_DISABLE_BINDLOCAL "OFF" diff --git a/src/tool_doswin.c b/src/tool_doswin.c index a64665bcd9..52eb69bd69 100644 --- a/src/tool_doswin.c +++ b/src/tool_doswin.c @@ -145,13 +145,13 @@ static SANITIZEcode msdosify(char ** const sanitized, const char *file_name, static const char illegal_chars_dos[] = ".+, ;=[]" /* illegal in DOS */ "|<>/\\\":?*"; /* illegal in DOS & W95 */ - static const char *illegal_chars_w95 = &illegal_chars_dos[8]; + static const char * const illegal_chars_w95 = &illegal_chars_dos[8]; int idx, dot_idx; const char *s = file_name; char *d = dos_name; - const char * const dlimit = dos_name + sizeof(dos_name) - 1; + const char * const dlimit = dos_name + CURL_CSTRLEN(dos_name); const char *illegal_aliens = illegal_chars_dos; - size_t len = sizeof(illegal_chars_dos) - 1; + size_t len = CURL_CSTRLEN(illegal_chars_dos); if(!sanitized) return SANITIZE_ERR_BAD_ARGUMENT; diff --git a/src/tool_easysrc.c b/src/tool_easysrc.c index 5b3c6cb45b..c2a34c3b2b 100644 --- a/src/tool_easysrc.c +++ b/src/tool_easysrc.c @@ -64,7 +64,7 @@ static const char * const srchard[] = { "", NULL }; -static const char *const srcend[] = { +static const char * const srcend[] = { "", " return (int)result;", "}", diff --git a/src/tool_formparse.c b/src/tool_formparse.c index 6d41711a40..450a2b3a99 100644 --- a/src/tool_formparse.c +++ b/src/tool_formparse.c @@ -509,7 +509,7 @@ static void param_type(char **ptr, char **ptype, char **endct, char *sep) { char *p = *ptr; size_t tlen; - for(p += sizeof("type=") - 1; ISBLANK(*p); p++) + for(p += CURL_CSTRLEN("type="); ISBLANK(*p); p++) ; /* set type pointer */ *ptype = p; @@ -533,7 +533,7 @@ static void param_filename(char **ptr, char **endct, char **pfilename, **endct = '\0'; *endct = NULL; } - for(p += sizeof("filename=") - 1; ISBLANK(*p); p++) + for(p += CURL_CSTRLEN("filename="); ISBLANK(*p); p++) ; tp = p; *pfilename = get_param_word(&p, &endpos, endchar); @@ -557,7 +557,7 @@ static int param_headers(char **ptr, char **endct, **endct = '\0'; *endct = NULL; } - p += sizeof("headers=") - 1; + p += CURL_CSTRLEN("headers="); if(*p == '@' || *p == '<') { char *hdrfile; FILE *fp; @@ -623,7 +623,7 @@ static void param_encoder(char **ptr, char **endct, char **pencoder, **endct = '\0'; *endct = NULL; } - for(p += sizeof("encoder=") - 1; ISBLANK(*p); p++) + for(p += CURL_CSTRLEN("encoder="); ISBLANK(*p); p++) ; tp = p; *pencoder = get_param_word(&p, &endpos, endchar); diff --git a/src/tool_getparam.c b/src/tool_getparam.c index 479168e0bd..73419ead09 100644 --- a/src/tool_getparam.c +++ b/src/tool_getparam.c @@ -2488,7 +2488,7 @@ static ParameterError opt_string(struct OperationConfig *config, { ParameterError err = PARAM_OK; curl_off_t value; - static const char *redir_protos[] = { + static const char * const redir_protos[] = { "http", "https", "ftp", diff --git a/src/tool_helpers.c b/src/tool_helpers.c index b5e9b54121..1b998d2ca6 100644 --- a/src/tool_helpers.c +++ b/src/tool_helpers.c @@ -77,7 +77,7 @@ const char *param2text(ParameterError error) int SetHTTPrequest(HttpReq req, HttpReq *store) { /* this mirrors the HttpReq enum in tool_sdecls.h */ - const char *reqname[] = { + static const char * const reqname[] = { "", /* unspec */ "GET (-G, --get)", "HEAD (-I, --head)", @@ -101,7 +101,7 @@ int SetHTTPrequest(HttpReq req, HttpReq *store) void customrequest_helper(HttpReq req, const char *method) { /* this mirrors the HttpReq enum in tool_sdecls.h */ - const char *dflt[] = { + static const char * const dflt[] = { "GET", "GET", "HEAD", diff --git a/src/tool_libinfo.c b/src/tool_libinfo.c index bce6bb7d6e..dfb23912f3 100644 --- a/src/tool_libinfo.c +++ b/src/tool_libinfo.c @@ -27,7 +27,7 @@ /* global variable definitions, for libcurl runtime info */ -static const char *no_protos = NULL; +static const char * const no_protos = NULL; curl_version_info_data *curlinfo = NULL; const char * const *built_in_protos = &no_protos; diff --git a/src/tool_paramhlp.c b/src/tool_paramhlp.c index 57a49ef97f..a3be2afcf7 100644 --- a/src/tool_paramhlp.c +++ b/src/tool_paramhlp.c @@ -297,7 +297,7 @@ ParameterError secs2ms(long *val, const char *str) { curl_off_t secs; long ms = 0; - const unsigned int digs[] = { + static const unsigned int digs[] = { 1, 10, 100, diff --git a/src/tool_progress.c b/src/tool_progress.c index c30644c0e3..d3ee694fea 100644 --- a/src/tool_progress.c +++ b/src/tool_progress.c @@ -35,7 +35,7 @@ UNITTEST char *max5data(curl_off_t bytes, char *max5, size_t mlen) { /* a signed 64-bit value is 8192 petabytes maximum */ - const char unit[] = { 'k', 'M', 'G', 'T', 'P', 'E', 0 }; + static const char unit[] = { 'k', 'M', 'G', 'T', 'P', 'E', 0 }; int k = 0; if(bytes < 100000) { curl_msnprintf(max5, mlen, "%5" CURL_FORMAT_CURL_OFF_T, bytes); diff --git a/src/var.c b/src/var.c index 8f9dbbb5b0..464b0c1c2c 100644 --- a/src/var.c +++ b/src/var.c @@ -62,15 +62,15 @@ static const struct tool_var *varcontent(const char *name, size_t nlen) (!strncmp(ptr, name, len) && ENDOFFUNC((ptr)[len])) #define FUNC_TRIM "trim" -#define FUNC_TRIM_LEN (sizeof(FUNC_TRIM) - 1) +#define FUNC_TRIM_LEN CURL_CSTRLEN(FUNC_TRIM) #define FUNC_JSON "json" -#define FUNC_JSON_LEN (sizeof(FUNC_JSON) - 1) +#define FUNC_JSON_LEN CURL_CSTRLEN(FUNC_JSON) #define FUNC_URL "url" -#define FUNC_URL_LEN (sizeof(FUNC_URL) - 1) +#define FUNC_URL_LEN CURL_CSTRLEN(FUNC_URL) #define FUNC_B64 "b64" -#define FUNC_B64_LEN (sizeof(FUNC_B64) - 1) +#define FUNC_B64_LEN CURL_CSTRLEN(FUNC_B64) #define FUNC_64DEC "64dec" /* base64 decode */ -#define FUNC_64DEC_LEN (sizeof(FUNC_64DEC) - 1) +#define FUNC_64DEC_LEN CURL_CSTRLEN(FUNC_64DEC) static ParameterError varfunc(char *c, /* content */ size_t clen, /* content length */ diff --git a/tests/http/testenv/mod_curltest/mod_curltest.c b/tests/http/testenv/mod_curltest/mod_curltest.c index 0bb0c78a36..d783af1ab6 100644 --- a/tests/http/testenv/mod_curltest/mod_curltest.c +++ b/tests/http/testenv/mod_curltest/mod_curltest.c @@ -949,7 +949,7 @@ static int curltest_post_config(apr_pool_t *p, apr_pool_t *plog, apr_pool_t *ptemp, server_rec *s) { void *data = NULL; - const char *key = "mod_curltest_init_counter"; + static const char *key = "mod_curltest_init_counter"; (void)p; (void)plog; diff --git a/tests/libtest/lib1514.c b/tests/libtest/lib1514.c index a799e7668d..528468eee0 100644 --- a/tests/libtest/lib1514.c +++ b/tests/libtest/lib1514.c @@ -29,7 +29,7 @@ #include "first.h" struct t1514_WriteThis { - char *readptr; + const char *readptr; size_t sizeleft; }; @@ -55,9 +55,9 @@ static CURLcode test_lib1514(const char *URL) CURL *curl; CURLcode result = CURLE_OK; - static char testdata[] = "dummy"; + static const char testdata[] = "dummy"; - struct t1514_WriteThis pooh = { testdata, sizeof(testdata) - 1 }; + struct t1514_WriteThis pooh = { testdata, CURL_CSTRLEN(testdata) }; global_init(CURL_GLOBAL_ALL); diff --git a/tests/libtest/lib1517.c b/tests/libtest/lib1517.c index 30e80a7bce..a88705ed68 100644 --- a/tests/libtest/lib1517.c +++ b/tests/libtest/lib1517.c @@ -60,7 +60,7 @@ static CURLcode test_lib1517(const char *URL) struct t1517_WriteThis pooh; pooh.readptr = testdata; - pooh.sizeleft = sizeof(testdata) - 1; + pooh.sizeleft = CURL_CSTRLEN(testdata); if(curl_global_init(CURL_GLOBAL_ALL)) { curl_mfprintf(stderr, "curl_global_init() failed\n"); diff --git a/tests/libtest/lib1520.c b/tests/libtest/lib1520.c index 9ed257591e..b97fd94fc8 100644 --- a/tests/libtest/lib1520.c +++ b/tests/libtest/lib1520.c @@ -29,7 +29,7 @@ struct upload_status { static size_t t1520_read_cb(char *ptr, size_t size, size_t nmemb, void *userp) { - static const char *payload_text[] = { + static const char * const payload_text[] = { "From: different\r\n", "To: another\r\n", "\r\n", diff --git a/tests/libtest/lib1525.c b/tests/libtest/lib1525.c index 3498941ea2..7465eb59dd 100644 --- a/tests/libtest/lib1525.c +++ b/tests/libtest/lib1525.c @@ -31,7 +31,7 @@ #include "first.h" static const char t1525_data[] = "Hello Cloud!\n"; -static size_t const t1525_datalen = sizeof(t1525_data) - 1; +static const size_t t1525_datalen = CURL_CSTRLEN(t1525_data); static size_t t1525_read_cb(char *ptr, size_t size, size_t nmemb, void *stream) { diff --git a/tests/libtest/lib1526.c b/tests/libtest/lib1526.c index 6e01804628..56b1b749b3 100644 --- a/tests/libtest/lib1526.c +++ b/tests/libtest/lib1526.c @@ -30,7 +30,7 @@ #include "first.h" static const char t1526_data[] = "Hello Cloud!\n"; -static size_t const t1526_datalen = sizeof(t1526_data) - 1; +static const size_t t1526_datalen = CURL_CSTRLEN(t1526_data); static size_t t1526_read_cb(char *ptr, size_t size, size_t nmemb, void *stream) { diff --git a/tests/libtest/lib1527.c b/tests/libtest/lib1527.c index ef438dc901..1caa37d8d3 100644 --- a/tests/libtest/lib1527.c +++ b/tests/libtest/lib1527.c @@ -30,7 +30,7 @@ #include "first.h" static const char t1527_data[] = "Hello Cloud!\n"; -static size_t const t1527_datalen = sizeof(t1527_data) - 1; +static const size_t t1527_datalen = CURL_CSTRLEN(t1527_data); static size_t t1527_read_cb(char *ptr, size_t size, size_t nmemb, void *stream) { diff --git a/tests/libtest/lib1531.c b/tests/libtest/lib1531.c index def737f9f1..20ac3639eb 100644 --- a/tests/libtest/lib1531.c +++ b/tests/libtest/lib1531.c @@ -25,8 +25,8 @@ static CURLcode test_lib1531(const char *URL) { - static char const testdata[] = ".abc\0xyz"; - static curl_off_t const testdatalen = sizeof(testdata) - 1; + static const char testdata[] = ".abc\0xyz"; + static const curl_off_t testdatalen = CURL_CSTRLEN(testdata); CURL *curl; CURLM *multi; diff --git a/tests/libtest/lib1537.c b/tests/libtest/lib1537.c index 1ef0be9c75..7fd91f9d4f 100644 --- a/tests/libtest/lib1537.c +++ b/tests/libtest/lib1537.c @@ -25,8 +25,10 @@ static CURLcode test_lib1537(const char *URL) { - const unsigned char a[] = { 0x2f, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, - 0x91, 0xa2, 0xb3, 0xc4, 0xd5, 0xe6, 0xf7 }; + static const unsigned char a[] = { + 0x2f, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, + 0x91, 0xa2, 0xb3, 0xc4, 0xd5, 0xe6, 0xf7 + }; CURLcode result = CURLE_OK; char *ptr = NULL; int asize; diff --git a/tests/libtest/lib1554.c b/tests/libtest/lib1554.c index 8b37374c5a..c553095c61 100644 --- a/tests/libtest/lib1554.c +++ b/tests/libtest/lib1554.c @@ -23,7 +23,7 @@ ***************************************************************************/ #include "first.h" -static const char *ldata_names[] = { +static const char * const ldata_names[] = { "NONE", "SHARE", "COOKIE", diff --git a/tests/libtest/lib1560.c b/tests/libtest/lib1560.c index 1c8aabfd5b..fafdd8de99 100644 --- a/tests/libtest/lib1560.c +++ b/tests/libtest/lib1560.c @@ -2269,7 +2269,7 @@ static char bigpart[120000]; */ static int huge(void) { - static const char *smallpart = "c"; + static const char smallpart[] = "c"; int i; CURLU *urlp = curl_url(); CURLUcode rc; @@ -2323,7 +2323,7 @@ static int huge(void) static int urldup(void) { - static const char *url[] = { + static const char * const url[] = { "http://" "user:pwd@" "[2a04:4e42:e00::347%25eth0]" diff --git a/tests/libtest/lib1576.c b/tests/libtest/lib1576.c index 64aaa4c5ea..a052519a25 100644 --- a/tests/libtest/lib1576.c +++ b/tests/libtest/lib1576.c @@ -23,8 +23,9 @@ ***************************************************************************/ #include "first.h" -static char t1576_data[] = "request indicates that the client, which made"; -static size_t const t1576_datalen = sizeof(t1576_data) - 1; +static const char t1576_data[] = "request indicates that the client, " + "which made"; +static const size_t t1576_datalen = CURL_CSTRLEN(t1576_data); static size_t t1576_read_cb(char *ptr, size_t size, size_t nmemb, void *stream) { diff --git a/tests/libtest/lib1591.c b/tests/libtest/lib1591.c index 97b234234f..427f966564 100644 --- a/tests/libtest/lib1591.c +++ b/tests/libtest/lib1591.c @@ -34,7 +34,7 @@ static size_t consumed = 0; static size_t t1591_read_cb(char *ptr, size_t size, size_t nmemb, void *stream) { static const char testdata[] = "Hello Cloud!\r\n"; - static size_t const datalen = sizeof(testdata) - 1; + static const size_t datalen = CURL_CSTRLEN(testdata); size_t amount = nmemb * size; /* Total bytes curl wants */ diff --git a/tests/libtest/lib1598.c b/tests/libtest/lib1598.c index 961c424e68..106a339c07 100644 --- a/tests/libtest/lib1598.c +++ b/tests/libtest/lib1598.c @@ -52,7 +52,7 @@ static int t1598_trailers_callback(struct curl_slist **list, void *userdata) static CURLcode test_lib1598(const char *URL) { - static const char *post_data = "xxx=yyy&aaa=bbbbb"; + static const char post_data[] = "xxx=yyy&aaa=bbbbb"; CURL *curl = NULL; CURLcode result = CURLE_FAILED_INIT; @@ -84,7 +84,7 @@ static CURLcode test_lib1598(const char *URL) easy_setopt(curl, CURLOPT_URL, URL); easy_setopt(curl, CURLOPT_HTTPHEADER, hhl); - easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)strlen(post_data)); + easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)CURL_CSTRLEN(post_data)); easy_setopt(curl, CURLOPT_POSTFIELDS, post_data); easy_setopt(curl, CURLOPT_TRAILERFUNCTION, t1598_trailers_callback); easy_setopt(curl, CURLOPT_TRAILERDATA, NULL); diff --git a/tests/libtest/lib1662.c b/tests/libtest/lib1662.c index 0e4942e9ad..4c338d2921 100644 --- a/tests/libtest/lib1662.c +++ b/tests/libtest/lib1662.c @@ -30,7 +30,7 @@ struct t1662_WriteThis { static size_t t1662_read_cb(char *ptr, size_t size, size_t nmemb, void *userp) { static const char testdata[] = "mooaaa"; - static size_t const testdatalen = sizeof(testdata) - 1; + static const size_t testdatalen = CURL_CSTRLEN(testdata); struct t1662_WriteThis *pooh = (struct t1662_WriteThis *)userp; diff --git a/tests/libtest/lib1901.c b/tests/libtest/lib1901.c index a6ccbdb0cb..dae52a7f2c 100644 --- a/tests/libtest/lib1901.c +++ b/tests/libtest/lib1901.c @@ -25,7 +25,7 @@ static size_t t1901_read_cb(char *ptr, size_t size, size_t nmemb, void *stream) { - static const char *chunks[] = { "one", "two", "three", "four", NULL }; + static const char * const chunks[] = { "one", "two", "three", "four", NULL }; static int ix = 0; (void)stream; if(chunks[ix]) { diff --git a/tests/libtest/lib1940.c b/tests/libtest/lib1940.c index 349d8131c6..a0fea9264f 100644 --- a/tests/libtest/lib1940.c +++ b/tests/libtest/lib1940.c @@ -25,7 +25,7 @@ static void t1940_showem(CURL *curl, int header_request, unsigned int type) { - static const char *testdata[] = { + static const char * const testdata[] = { "daTE", "Server", "content-type", diff --git a/tests/libtest/lib1948.c b/tests/libtest/lib1948.c index 9b8217be8f..73bd5d7ba0 100644 --- a/tests/libtest/lib1948.c +++ b/tests/libtest/lib1948.c @@ -55,9 +55,9 @@ static CURLcode test_lib1948(const char *URL) easy_setopt(curl, CURLOPT_HEADER, 1L); easy_setopt(curl, CURLOPT_READFUNCTION, put_callback); pbuf.buf = testput; - pbuf.len = sizeof(testput) - 1; + pbuf.len = CURL_CSTRLEN(testput); easy_setopt(curl, CURLOPT_READDATA, &pbuf); - easy_setopt(curl, CURLOPT_INFILESIZE, (long)(sizeof(testput) - 1)); + easy_setopt(curl, CURLOPT_INFILESIZE, (long)CURL_CSTRLEN(testput)); easy_setopt(curl, CURLOPT_URL, URL); result = curl_easy_perform(curl); if(result) @@ -66,7 +66,7 @@ static CURLcode test_lib1948(const char *URL) /* POST */ easy_setopt(curl, CURLOPT_POST, 1L); easy_setopt(curl, CURLOPT_POSTFIELDS, testput); - easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)(sizeof(testput) - 1)); + easy_setopt(curl, CURLOPT_POSTFIELDSIZE, (long)CURL_CSTRLEN(testput)); result = curl_easy_perform(curl); test_cleanup: diff --git a/tests/libtest/lib1965.c b/tests/libtest/lib1965.c index e09ff349b3..683e5a716a 100644 --- a/tests/libtest/lib1965.c +++ b/tests/libtest/lib1965.c @@ -27,7 +27,7 @@ static CURLcode test_lib1965(const char *URL) { CURLcode result = CURLE_OK; CURLUcode rc; - static const char *schemes[] = { + static const char * const schemes[] = { "bad!", "bad{", "bad/", "bad\\", "a!", "a+123", "http-2", "http.1", "a+-.123", "http-+++2", "http.1--", diff --git a/tests/libtest/lib3102.c b/tests/libtest/lib3102.c index 59db9e45f1..312d5e600e 100644 --- a/tests/libtest/lib3102.c +++ b/tests/libtest/lib3102.c @@ -47,11 +47,11 @@ static bool is_chain_in_order(struct curl_certinfo *cert_info) static const char issuer_prefix[] = "Issuer:"; static const char subject_prefix[] = "Subject:"; - if(!strncmp(slist->data, issuer_prefix, sizeof(issuer_prefix) - 1)) { - issuer = slist->data + sizeof(issuer_prefix) - 1; + if(!strncmp(slist->data, issuer_prefix, CURL_CSTRLEN(issuer_prefix))) { + issuer = slist->data + CURL_CSTRLEN(issuer_prefix); } - if(!strncmp(slist->data, subject_prefix, sizeof(subject_prefix) - 1)) { - subject = slist->data + sizeof(subject_prefix) - 1; + if(!strncmp(slist->data, subject_prefix, CURL_CSTRLEN(subject_prefix))) { + subject = slist->data + CURL_CSTRLEN(subject_prefix); } } diff --git a/tests/libtest/lib505.c b/tests/libtest/lib505.c index 7abaacd14e..bf1310fcd2 100644 --- a/tests/libtest/lib505.c +++ b/tests/libtest/lib505.c @@ -41,8 +41,8 @@ static CURLcode test_lib505(const char *URL) struct curl_slist *headerlist; struct curl_slist *temp; - static const char *buf_1 = "RNFR 505"; - static const char *buf_2 = "RNTO 505-forreal"; + static const char buf_1[] = "RNFR 505"; + static const char buf_2[] = "RNTO 505-forreal"; if(!libtest_arg2) { curl_mfprintf(stderr, "Usage: \n"); diff --git a/tests/libtest/lib508.c b/tests/libtest/lib508.c index 7ecf2665c4..20aa1ff865 100644 --- a/tests/libtest/lib508.c +++ b/tests/libtest/lib508.c @@ -56,7 +56,7 @@ static CURLcode test_lib508(const char *URL) struct t508_WriteThis pooh; pooh.readptr = testdata; - pooh.sizeleft = sizeof(testdata) - 1; + pooh.sizeleft = CURL_CSTRLEN(testdata); if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { curl_mfprintf(stderr, "curl_global_init() failed\n"); diff --git a/tests/libtest/lib536.c b/tests/libtest/lib536.c index e25922062a..d6347545f5 100644 --- a/tests/libtest/lib536.c +++ b/tests/libtest/lib536.c @@ -37,7 +37,7 @@ static CURLcode test_lib536(const char *URL) CURL *curl; struct curl_slist *host = NULL; - static const char *url_with_proxy = "http://usingproxy.test/"; + static const char url_with_proxy[] = "http://usingproxy.test/"; const char *url_without_proxy = libtest_arg2; if(curl_global_init(CURL_GLOBAL_ALL) != CURLE_OK) { diff --git a/tests/libtest/lib544.c b/tests/libtest/lib544.c index 02dc11f39b..013c2ab32b 100644 --- a/tests/libtest/lib544.c +++ b/tests/libtest/lib544.c @@ -63,7 +63,7 @@ static CURLcode test_lib544(const char *URL) easy_setopt(curl, CURLOPT_HEADER, 1L); /* include header */ /* Update the original data to detect non-copy. */ - curlx_strcopy(teststring, sizeof(teststring), "FAIL", strlen("FAIL")); + curlx_strcopy(teststring, sizeof(teststring), "FAIL", CURL_CSTRLEN("FAIL")); { CURL *curl2; diff --git a/tests/libtest/lib547.c b/tests/libtest/lib547.c index e44c16b55b..66ad32afbb 100644 --- a/tests/libtest/lib547.c +++ b/tests/libtest/lib547.c @@ -29,7 +29,7 @@ #include "first.h" static const char t547_uploadthis[] = "this is the blurb we want to upload\n"; -static size_t const t547_datalen = sizeof(t547_uploadthis) - 1; +static const size_t t547_datalen = CURL_CSTRLEN(t547_uploadthis); static size_t t547_read_cb(char *ptr, size_t size, size_t nmemb, void *clientp) { diff --git a/tests/libtest/lib554.c b/tests/libtest/lib554.c index 98a7ba7fdc..ce4348a8d7 100644 --- a/tests/libtest/lib554.c +++ b/tests/libtest/lib554.c @@ -69,7 +69,7 @@ static CURLcode t554_test_once(const char *URL, bool oldstyle) struct t554_WriteThis pooh2; pooh.readptr = testdata; - pooh.sizeleft = sizeof(testdata) - 1; + pooh.sizeleft = CURL_CSTRLEN(testdata); /* Fill in the file upload field */ if(oldstyle) { @@ -99,7 +99,7 @@ static CURLcode t554_test_once(const char *URL, bool oldstyle) a file upload but still using the callback */ pooh2.readptr = testdata; - pooh2.sizeleft = sizeof(testdata) - 1; + pooh2.sizeleft = CURL_CSTRLEN(testdata); /* Fill in the file upload field */ formrc = curl_formadd(&formpost, diff --git a/tests/libtest/lib555.c b/tests/libtest/lib555.c index 9e11aae7d7..e2cdfbc971 100644 --- a/tests/libtest/lib555.c +++ b/tests/libtest/lib555.c @@ -33,7 +33,7 @@ #include "first.h" static const char t555_uploadthis[] = "this is the blurb we want to upload\n"; -static size_t const t555_datalen = sizeof(t555_uploadthis) - 1; +static const size_t t555_datalen = CURL_CSTRLEN(t555_uploadthis); static size_t t555_read_cb(char *ptr, size_t size, size_t nmemb, void *clientp) { diff --git a/tests/libtest/lib571.c b/tests/libtest/lib571.c index 37b93e5390..4f506bc3b9 100644 --- a/tests/libtest/lib571.c +++ b/tests/libtest/lib571.c @@ -44,7 +44,7 @@ static int rtp_packet_count = 0; static size_t rtp_write(char *data, size_t size, size_t nmemb, void *stream) { - static const char *RTP_DATA = "$_1234\n\0Rsdf"; + static const char RTP_DATA[] = "$_1234\n\0Rsdf"; int channel = RTP_PKT_CHANNEL(data); int message_size; diff --git a/tests/libtest/lib643.c b/tests/libtest/lib643.c index eaf75e8fe1..c2aed4f0d2 100644 --- a/tests/libtest/lib643.c +++ b/tests/libtest/lib643.c @@ -69,7 +69,7 @@ static CURLcode t643_test_once(const char *URL, bool oldstyle) pooh.readptr = testdata; if(testnum == 643) - datasize = (curl_off_t)(sizeof(testdata) - 1); + datasize = (curl_off_t)CURL_CSTRLEN(testdata); pooh.sizeleft = datasize; curl = curl_easy_init(); @@ -123,7 +123,7 @@ static CURLcode t643_test_once(const char *URL, bool oldstyle) pooh2.readptr = testdata; if(testnum == 643) - datasize = (curl_off_t)(sizeof(testdata) - 1); + datasize = (curl_off_t)CURL_CSTRLEN(testdata); pooh2.sizeleft = datasize; part = curl_mime_addpart(mime); diff --git a/tests/libtest/lib654.c b/tests/libtest/lib654.c index 0494d580ab..a10dc94478 100644 --- a/tests/libtest/lib654.c +++ b/tests/libtest/lib654.c @@ -92,7 +92,7 @@ static CURLcode test_lib654(const char *URL) /* Prepare the callback structure. */ pooh.readptr = testdata; - pooh.sizeleft = (curl_off_t)(sizeof(testdata) - 1); + pooh.sizeleft = (curl_off_t)CURL_CSTRLEN(testdata); pooh.freecount = 0; /* Build the mime tree. */ diff --git a/tests/libtest/lib655.c b/tests/libtest/lib655.c index 3dd70dfa73..5e1f0990e2 100644 --- a/tests/libtest/lib655.c +++ b/tests/libtest/lib655.c @@ -25,7 +25,7 @@ #include "testtrace.h" -static const char *TEST_DATA_STRING = "Test data"; +static const char TEST_DATA_STRING[] = "Test data"; static int cb_count = 0; static int resolver_alloc_cb_fail(void *resolver_state, void *reserved, diff --git a/tests/libtest/lib667.c b/tests/libtest/lib667.c index 28a9cde6d2..38158dc2b4 100644 --- a/tests/libtest/lib667.c +++ b/tests/libtest/lib667.c @@ -82,7 +82,7 @@ static CURLcode test_lib667(const char *URL) /* Prepare the callback structure. */ pooh.readptr = testdata; - pooh.sizeleft = (curl_off_t)(sizeof(testdata) - 1); + pooh.sizeleft = (curl_off_t)CURL_CSTRLEN(testdata); /* Build the mime tree. */ mime = curl_mime_init(curl); diff --git a/tests/libtest/lib668.c b/tests/libtest/lib668.c index cd9897f7e9..fd59a0c3f9 100644 --- a/tests/libtest/lib668.c +++ b/tests/libtest/lib668.c @@ -77,7 +77,7 @@ static CURLcode test_lib668(const char *URL) /* Prepare the callback structures. */ pooh1.readptr = testdata; - pooh1.sizeleft = sizeof(testdata) - 1; + pooh1.sizeleft = CURL_CSTRLEN(testdata); pooh2 = pooh1; /* Build the mime tree. */ diff --git a/tests/libtest/lib677.c b/tests/libtest/lib677.c index 106fbb2603..6a6c5ef5a9 100644 --- a/tests/libtest/lib677.c +++ b/tests/libtest/lib677.c @@ -77,8 +77,8 @@ static CURLcode test_lib677(const char *URL) if(!state) { CURLcode ec; - ec = curl_easy_send(curl, testcmd + pos, - sizeof(testcmd) - 1 - pos, &len); + ec = curl_easy_send(curl, testcmd + pos, CURL_CSTRLEN(testcmd) - pos, + &len); if(ec == CURLE_AGAIN) { continue; } @@ -92,7 +92,7 @@ static CURLcode test_lib677(const char *URL) pos += len; else pos = 0; - if(pos == sizeof(testcmd) - 1) { + if(pos == CURL_CSTRLEN(testcmd)) { state++; pos = 0; } diff --git a/tests/libtest/lib757.c b/tests/libtest/lib757.c index 325f3b7b6b..378c78cf81 100644 --- a/tests/libtest/lib757.c +++ b/tests/libtest/lib757.c @@ -24,7 +24,7 @@ #include "first.h" static const char t757_data[] = "fun-times"; -static size_t const t757_datalen = sizeof(t757_data) - 1; +static const size_t t757_datalen = CURL_CSTRLEN(t757_data); static size_t read_757(char *buffer, size_t size, size_t nitems, void *arg) { diff --git a/tests/server/mqttd.c b/tests/server/mqttd.c index 189ac41bec..732bcd2efb 100644 --- a/tests/server/mqttd.c +++ b/tests/server/mqttd.c @@ -178,8 +178,8 @@ static int connack(FILE *dump, curl_socket_t fd) MQTT_MSG_CONNACK, 0x02, 0x00, 0x00 }; - ssize_t rc; const char *label = "CONNACK"; + ssize_t rc; if(m_config.pingresp_as_connack) { /* Send a PINGRESP (0xD0) with remaining_length=2 and payload @@ -260,8 +260,8 @@ static int disconnect(FILE *dump, curl_socket_t fd) MQTT_MSG_DISCONNECT, 0x00, 0x00, 0x00 /* extra bytes for malformed variant */ }; - size_t pktlen = 2; const char *label = "DISCONNECT"; + size_t pktlen = 2; ssize_t rc; if(m_config.disconnect_malformed) { @@ -638,8 +638,8 @@ static curl_socket_t mqttit(curl_socket_t fd) } } else { - const char *def = "this is random payload yes yes it is"; - publish(dump, fd, packet_id, topic, def, strlen(def)); + static const char def[] = "this is random payload yes yes it is"; + publish(dump, fd, packet_id, topic, def, CURL_CSTRLEN(def)); } disconnect(dump, fd); } diff --git a/tests/server/rtspd.c b/tests/server/rtspd.c index fe2dded9fa..7e6c8ef43b 100644 --- a/tests/server/rtspd.c +++ b/tests/server/rtspd.c @@ -106,18 +106,18 @@ struct rtspd_httprequest { #define END_OF_HEADERS "\r\n\r\n" /* sent as reply to a QUIT */ -static const char *docquit_rtsp = "HTTP/1.1 200 Goodbye" END_OF_HEADERS; +static const char docquit_rtsp[] = "HTTP/1.1 200 Goodbye" END_OF_HEADERS; /* sent as reply to a CONNECT */ -static const char *docconnect = +static const char docconnect[] = "HTTP/1.1 200 Mighty fine indeed" END_OF_HEADERS; /* sent as reply to a "bad" CONNECT */ -static const char *docbadconnect = +static const char docbadconnect[] = "HTTP/1.1 501 Forbidden you fool" END_OF_HEADERS; /* send back this on HTTP 404 file not found */ -static const char *doc404_HTTP = +static const char doc404_HTTP[] = "HTTP/1.1 404 Not Found\r\n" "Server: " RTSPDVERSION "\r\n" "Connection: close\r\n" @@ -133,13 +133,13 @@ static const char *doc404_HTTP = "\n"; /* send back this on RTSP 404 file not found */ -static const char *doc404_RTSP = "RTSP/1.0 404 Not Found\r\n" +static const char doc404_RTSP[] = "RTSP/1.0 404 Not Found\r\n" "Server: " RTSPDVERSION END_OF_HEADERS; /* Default size to send away fake RTP data */ #define RTP_DATA_SIZE 12 -static const char *RTP_DATA = "$_1234\n\0Rsdf"; +static const char RTP_DATA[] = "$_1234\n\0Rsdf"; static int rtspd_ProcessRequest(struct rtspd_httprequest *req) { @@ -267,16 +267,17 @@ static int rtspd_ProcessRequest(struct rtspd_httprequest *req) logmsg("Found a reply-servercmd section!"); do { rtp_size_err = 0; - if(!strncmp(CMD_AUTH_REQUIRED, ptr, strlen(CMD_AUTH_REQUIRED))) { + if(!strncmp(CMD_AUTH_REQUIRED, ptr, + CURL_CSTRLEN(CMD_AUTH_REQUIRED))) { logmsg("instructed to require authorization header"); req->auth_req = TRUE; } - else if(!strncmp(CMD_IDLE, ptr, strlen(CMD_IDLE))) { + else if(!strncmp(CMD_IDLE, ptr, CURL_CSTRLEN(CMD_IDLE))) { logmsg("instructed to idle"); req->rcmd = RCMD_IDLE; req->open = TRUE; } - else if(!strncmp(CMD_STREAM, ptr, strlen(CMD_STREAM))) { + else if(!strncmp(CMD_STREAM, ptr, CURL_CSTRLEN(CMD_STREAM))) { logmsg("instructed to stream"); req->rcmd = RCMD_STREAM; } @@ -404,7 +405,7 @@ static int rtspd_ProcessRequest(struct rtspd_httprequest *req) if(req->pipe) /* we do have a full set, advance the checkindex to after the end of the headers, for the pipelining case mostly */ - req->checkindex += (end - line) + strlen(END_OF_HEADERS); + req->checkindex += (end - line) + CURL_CSTRLEN(END_OF_HEADERS); /* **** Persistence **** * @@ -427,7 +428,7 @@ static int rtspd_ProcessRequest(struct rtspd_httprequest *req) ignore the content-length, we return as soon as all headers have been received */ curl_off_t clen; - const char *p = line + strlen("Content-Length:"); + const char *p = line + CURL_CSTRLEN("Content-Length:"); if(curlx_str_numblanks(&p, &clen)) { /* this assumes that a zero Content-Length is valid */ logmsg("Found invalid '%s' in the request", line); @@ -442,7 +443,7 @@ static int rtspd_ProcessRequest(struct rtspd_httprequest *req) break; } else if(!CURL_STRNICMP("Transfer-Encoding: chunked", line, - strlen("Transfer-Encoding: chunked"))) { + CURL_CSTRLEN("Transfer-Encoding: chunked"))) { /* chunked data coming in */ chunked = TRUE; } @@ -506,12 +507,12 @@ static int rtspd_ProcessRequest(struct rtspd_httprequest *req) if(!req->pipe && req->open && req->prot_version >= 11 && - req->reqbuf + req->offset > end + strlen(END_OF_HEADERS) && - (!strncmp(req->reqbuf, "GET", strlen("GET")) || - !strncmp(req->reqbuf, "HEAD", strlen("HEAD")))) { + req->reqbuf + req->offset > end + CURL_CSTRLEN(END_OF_HEADERS) && + (!strncmp(req->reqbuf, "GET", CURL_CSTRLEN("GET")) || + !strncmp(req->reqbuf, "HEAD", CURL_CSTRLEN("HEAD")))) { /* If we have a persistent connection, HTTP version >= 1.1 and GET/HEAD request, enable pipelining. */ - req->checkindex = (end - req->reqbuf) + strlen(END_OF_HEADERS); + req->checkindex = (end - req->reqbuf) + CURL_CSTRLEN(END_OF_HEADERS); req->pipelining = TRUE; } @@ -523,7 +524,7 @@ static int rtspd_ProcessRequest(struct rtspd_httprequest *req) end = strstr(line, END_OF_HEADERS); if(!end) break; - req->checkindex += (end - line) + strlen(END_OF_HEADERS); + req->checkindex += (end - line) + CURL_CSTRLEN(END_OF_HEADERS); req->pipe--; } @@ -535,7 +536,8 @@ static int rtspd_ProcessRequest(struct rtspd_httprequest *req) return 1; /* done */ if(req->cl > 0) { - if(req->cl <= req->offset - (end - req->reqbuf) - strlen(END_OF_HEADERS)) + if(req->cl <= req->offset - (end - req->reqbuf) - + CURL_CSTRLEN(END_OF_HEADERS)) return 1; /* done */ else return 0; /* not complete yet */ diff --git a/tests/server/socksd.c b/tests/server/socksd.c index b0b5b6771c..4de563b06c 100644 --- a/tests/server/socksd.c +++ b/tests/server/socksd.c @@ -102,9 +102,9 @@ static void socksd_resetdefaults(void) curlx_strcopy(s_config.addr, sizeof(s_config.addr), CONFIG_ADDR, strlen(CONFIG_ADDR)); curlx_strcopy(s_config.user, sizeof(s_config.user), - "user", strlen("user")); + "user", CURL_CSTRLEN("user")); curlx_strcopy(s_config.password, sizeof(s_config.password), - "password", strlen("password")); + "password", CURL_CSTRLEN("password")); } static void socksd_getconfig(void) diff --git a/tests/server/sws.c b/tests/server/sws.c index 8190002af2..e47ba7fc3d 100644 --- a/tests/server/sws.c +++ b/tests/server/sws.c @@ -141,10 +141,10 @@ static const char *cmdfile = "log/server.cmd"; static const char *end_of_headers = END_OF_HEADERS; /* sent as reply to a QUIT */ -static const char *docquit_sws = "HTTP/1.1 200 Goodbye" END_OF_HEADERS; +static const char docquit_sws[] = "HTTP/1.1 200 Goodbye" END_OF_HEADERS; /* send back this on 404 file not found */ -static const char *doc404 = +static const char doc404[] = "HTTP/1.1 404 Not Found\r\n" "Server: " SWSVERSION "\r\n" "Connection: close\r\n" @@ -262,29 +262,29 @@ static int sws_parse_servercmd(struct sws_httprequest *req) while(cmd && cmdsize) { const char *check; - if(!strncmp(CMD_AUTH_REQUIRED, cmd, strlen(CMD_AUTH_REQUIRED))) { + if(!strncmp(CMD_AUTH_REQUIRED, cmd, CURL_CSTRLEN(CMD_AUTH_REQUIRED))) { logmsg("instructed to require authorization header"); req->auth_req = TRUE; } - else if(!strncmp(CMD_IDLE, cmd, strlen(CMD_IDLE))) { + else if(!strncmp(CMD_IDLE, cmd, CURL_CSTRLEN(CMD_IDLE))) { logmsg("instructed to idle"); req->rcmd = RCMD_IDLE; req->open = TRUE; } - else if(!strncmp(CMD_STREAM, cmd, strlen(CMD_STREAM))) { + else if(!strncmp(CMD_STREAM, cmd, CURL_CSTRLEN(CMD_STREAM))) { logmsg("instructed to stream"); req->rcmd = RCMD_STREAM; } else if(!strncmp(CMD_CONNECTIONMONITOR, cmd, - strlen(CMD_CONNECTIONMONITOR))) { + CURL_CSTRLEN(CMD_CONNECTIONMONITOR))) { logmsg("enabled connection monitoring"); req->connmon = TRUE; } - else if(!strncmp(CMD_UPGRADE, cmd, strlen(CMD_UPGRADE))) { + else if(!strncmp(CMD_UPGRADE, cmd, CURL_CSTRLEN(CMD_UPGRADE))) { logmsg("enabled upgrade"); req->upgrade = TRUE; } - else if(!strncmp(CMD_SWSCLOSE, cmd, strlen(CMD_SWSCLOSE))) { + else if(!strncmp(CMD_SWSCLOSE, cmd, CURL_CSTRLEN(CMD_SWSCLOSE))) { logmsg("swsclose: close this connection after response"); req->close = TRUE; } @@ -292,7 +292,7 @@ static int sws_parse_servercmd(struct sws_httprequest *req) logmsg("instructed to skip this number of bytes %d", num); req->skip = num; } - else if(!strncmp(CMD_NOEXPECT, cmd, strlen(CMD_NOEXPECT))) { + else if(!strncmp(CMD_NOEXPECT, cmd, CURL_CSTRLEN(CMD_NOEXPECT))) { logmsg("instructed to reject Expect: 100-continue"); req->noexpect = TRUE; } @@ -591,7 +591,7 @@ static int sws_ProcessRequest(struct sws_httprequest *req) ignore the content-length, we return as soon as all headers have been received */ curl_off_t clen; - const char *p = line + strlen("Content-Length:"); + const char *p = line + CURL_CSTRLEN("Content-Length:"); if(curlx_str_numblanks(&p, &clen)) { /* this assumes that a zero Content-Length is valid */ logmsg("Found invalid '%s' in the request", line); @@ -608,12 +608,13 @@ static int sws_ProcessRequest(struct sws_httprequest *req) logmsg("... but going to abort after %zu bytes", req->cl); } else if(!CURL_STRNICMP("Transfer-Encoding: chunked", line, - strlen("Transfer-Encoding: chunked"))) { + CURL_CSTRLEN("Transfer-Encoding: chunked"))) { /* chunked data coming in */ chunked = TRUE; } - else if(req->noexpect && !CURL_STRNICMP("Expect: 100-continue", line, - strlen("Expect: 100-continue"))) { + else if(req->noexpect && + !CURL_STRNICMP("Expect: 100-continue", line, + CURL_CSTRLEN("Expect: 100-continue"))) { if(req->cl) req->cl = 0; req->skipall = TRUE; @@ -709,8 +710,8 @@ static int sws_ProcessRequest(struct sws_httprequest *req) req->prot_version >= 11 && req->reqbuf + req->offset > end + strlen(end_of_headers) && !req->cl && - (!strncmp(req->reqbuf, "GET", strlen("GET")) || - !strncmp(req->reqbuf, "HEAD", strlen("HEAD")))) { + (!strncmp(req->reqbuf, "GET", CURL_CSTRLEN("GET")) || + !strncmp(req->reqbuf, "HEAD", CURL_CSTRLEN("HEAD")))) { /* If we have a persistent connection, HTTP version >= 1.1 and GET/HEAD request, enable pipelining. */ req->checkindex = (end - req->reqbuf) + strlen(end_of_headers); @@ -771,10 +772,10 @@ static int sws_send_doc(curl_socket_t sock, struct sws_httprequest *req) case RCMD_STREAM: { static const char streamthis[] = "a string to stream 01234567890\n"; for(;;) { - written = swrite(sock, streamthis, sizeof(streamthis) - 1); + written = swrite(sock, streamthis, CURL_CSTRLEN(streamthis)); if(got_exit_signal) return -1; - if(written != (ssize_t)(sizeof(streamthis) - 1)) { + if(written != (ssize_t)CURL_CSTRLEN(streamthis)) { logmsg("Stopped streaming"); break; } @@ -2325,8 +2326,9 @@ static int test_sws(int argc, const char *argv[]) logmsg("====> Client disconnect %d", req->connmon); if(req->connmon) { - const char *keepopen = "[DISCONNECT]\n"; - storerequest(keepopen, strlen(keepopen), REQUEST_DUMP_FILENAME); + static const char keepopen[] = "[DISCONNECT]\n"; + storerequest(keepopen, CURL_CSTRLEN(keepopen), + REQUEST_DUMP_FILENAME); } if(!req->open) diff --git a/tests/tunit/tool1720.c b/tests/tunit/tool1720.c index 80e3c157ba..486d57e630 100644 --- a/tests/tunit/tool1720.c +++ b/tests/tunit/tool1720.c @@ -28,7 +28,7 @@ static CURLcode test_tool1720(const char *arg) { UNITTEST_BEGIN_SIMPLE - static const char *check[] = { + static const char * const check[] = { "", "(null)", "filename", diff --git a/tests/unit/unit1303.c b/tests/unit/unit1303.c index 50cdaa12f1..52a7ea9c43 100644 --- a/tests/unit/unit1303.c +++ b/tests/unit/unit1303.c @@ -85,7 +85,7 @@ static CURLcode test_unit1303(const char *arg) const char *comment; }; - const struct timetest run[] = { + static const struct timetest run[] = { /* both timeouts set, not connecting */ {BASE + 4, 0, 10000, 8000, FALSE, 6000, "6 seconds should be left"}, {BASE + 4, 990000, 10000, 8000, FALSE, 5010, "5010 ms should be left"}, diff --git a/tests/unit/unit1395.c b/tests/unit/unit1395.c index d25d0e3005..a286303977 100644 --- a/tests/unit/unit1395.c +++ b/tests/unit/unit1395.c @@ -35,7 +35,7 @@ static CURLcode test_unit1395(const char *arg) const char *output; }; - const struct dotdot pairs[] = { + static const struct dotdot pairs[] = { { "/%2f%2e%2e%2f/../a", "/a" }, { "/%2f%2e%2e%2f/../", "/" }, { "/%2f%2e%2e%2f/.", "/%2f%2e%2e%2f/" }, diff --git a/tests/unit/unit1396.c b/tests/unit/unit1396.c index 5b03e092bb..1dd3c17112 100644 --- a/tests/unit/unit1396.c +++ b/tests/unit/unit1396.c @@ -51,7 +51,7 @@ static CURLcode test_unit1396(const char *arg) }; /* unescape, this => that */ - const struct test list1[] = { + static const struct test list1[] = { { "%61", 3, "a", 1 }, { "%61a", 4, "aa", 2 }, { "%61b", 4, "ab", 2 }, @@ -67,7 +67,7 @@ static CURLcode test_unit1396(const char *arg) { NULL, 0, NULL, 0 } /* end of list marker */ }; /* escape, this => that */ - const struct test list2[] = { + static const struct test list2[] = { { "a", 1, "a", 1 }, { "/", 1, "%2F", 3 }, { "a=b", 3, "a%3Db", 5 }, diff --git a/tests/unit/unit1398.c b/tests/unit/unit1398.c index 7f2267e438..2147a4a283 100644 --- a/tests/unit/unit1398.c +++ b/tests/unit/unit1398.c @@ -34,7 +34,7 @@ static CURLcode test_unit1398(const char *arg) int rc; char buf[3] = { 'b', 'u', 'g' }; - static const char *str = "bug"; + static const char str[] = "bug"; int width = 3; char output[130]; diff --git a/tests/unit/unit1625.c b/tests/unit/unit1625.c index 9ca59b9402..21e37370c1 100644 --- a/tests/unit/unit1625.c +++ b/tests/unit/unit1625.c @@ -41,8 +41,8 @@ static CURLcode test_unit1625(const char *arg) char *large; size_t i; const size_t large_value_len = MAX_HTTP_RESP_HEADER_SIZE; - const size_t large_prefix_len = strlen("Encoding: "); - const size_t large_suffix_len = strlen(", chunked"); + const size_t large_prefix_len = CURL_CSTRLEN("Encoding: "); + const size_t large_suffix_len = CURL_CSTRLEN(", chunked"); static const struct check1625 list[] = { /* basic case */ { "Encoding: gzip, chunked", "Encoding:", "chunked", TRUE }, diff --git a/tests/unit/unit1627.c b/tests/unit/unit1627.c index 1d1f598358..06bd30cff5 100644 --- a/tests/unit/unit1627.c +++ b/tests/unit/unit1627.c @@ -32,7 +32,7 @@ static CURLcode test_unit1627(const char *arg) size_t i, j; /* existing schemes in different cases */ - static const char *okay[] = { + static const char * const okay[] = { /* all upper */ "DICT", "FILE", "FTP", "FTPS", "GOPHER", "GOPHERS", "HTTP", "HTTPS", "IMAP", "IMAPS", "LDAP", "LDAPS", "MQTT", "MQTTS", "POP3", "POP3S", @@ -50,7 +50,7 @@ static CURLcode test_unit1627(const char *arg) "TELNEt", "tFTP", "Ws", "wSS", }; /* non-existing schemes */ - static const char *notokay[] = { + static const char * const notokay[] = { "a", "A", "htt", "ttp", "httt", "http+", "HTTPP", "HTTPPS", "HTTSP", "GROPHER", "D1CT", "AbG", "zLQp", "mNrtW", "PkY", "bVcxZq", "LmO", "iUhyT", "rEwQA", "xSdfG", "nBvC", "pOiuY", "tRewQ", "aSdfG", "hJkl", diff --git a/tests/unit/unit1650.c b/tests/unit/unit1650.c index 4e307474fd..299a19bfd4 100644 --- a/tests/unit/unit1650.c +++ b/tests/unit/unit1650.c @@ -54,8 +54,10 @@ static CURLcode test_unit1650(const char *arg) }; static const struct dohrequest req[] = { - {"test.host.name", CURL_DNS_TYPE_A, DNS_Q1, sizeof(DNS_Q1)-1, DOH_OK }, - {"test.host.name", CURL_DNS_TYPE_AAAA, DNS_Q2, sizeof(DNS_Q2)-1, DOH_OK }, + {"test.host.name", + CURL_DNS_TYPE_A, DNS_Q1, CURL_CSTRLEN(DNS_Q1), DOH_OK }, + {"test.host.name", + CURL_DNS_TYPE_AAAA, DNS_Q2, CURL_CSTRLEN(DNS_Q2), DOH_OK }, {"zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" ".host.name", CURL_DNS_TYPE_AAAA, NULL, 0, DOH_DNS_BAD_LABEL } @@ -235,7 +237,7 @@ static CURLcode test_unit1650(const char *arg) } /* pass all sizes into the decoder until full */ - for(i = 0; i < sizeof(full49) - 1; i++) { + for(i = 0; i < CURL_CSTRLEN(full49); i++) { struct dohentry d; DOHcode rc; memset(&d, 0, sizeof(d)); @@ -267,8 +269,8 @@ static CURLcode test_unit1650(const char *arg) struct dohentry d; struct dohaddr *a; memset(&d, 0, sizeof(d)); - rc = doh_resp_decode((const unsigned char *)full49, - sizeof(full49) - 1, CURL_DNS_TYPE_A, &d); + rc = doh_resp_decode((const unsigned char *)full49, CURL_CSTRLEN(full49), + CURL_DNS_TYPE_A, &d); fail_if(d.numaddr != 1, "missing address"); a = &d.addr[0]; p = &a->ip.v4[0]; diff --git a/tests/unit/unit1655.c b/tests/unit/unit1655.c index ff3dc53481..55e9020989 100644 --- a/tests/unit/unit1655.c +++ b/tests/unit/unit1655.c @@ -132,9 +132,9 @@ static CURLcode test_unit1655(const char *arg) const size_t buflen = sizeof(buffer); const size_t magic1 = 9765; size_t olen1 = magic1; - static const char *sunshine1 = "a.com"; - static const char *dotshine1 = "a.com."; - static const char *sunshine2 = "aa.com"; + static const char sunshine1[] = "a.com"; + static const char dotshine1[] = "a.com."; + static const char sunshine2[] = "aa.com"; size_t olen2; DOHcode ret2; size_t olen; diff --git a/tests/unit/unit1664.c b/tests/unit/unit1664.c index 17a04a37f2..f4574d485c 100644 --- a/tests/unit/unit1664.c +++ b/tests/unit/unit1664.c @@ -41,7 +41,7 @@ static CURLcode test_unit1664(const char *arg) { UNITTEST_BEGIN(t1664_setup()) - static const char *wordparse[] = { + static const char * const wordparse[] = { "word", "word ", " word ", @@ -78,7 +78,7 @@ static CURLcode test_unit1664(const char *arg) } { - static const char *qwords[] = { + static const char * const qwords[] = { "\"word\"", "\"word", "word\"", @@ -112,7 +112,7 @@ static CURLcode test_unit1664(const char *arg) } { - static const char *single[] = { + static const char * const single[] = { "a", "aa", "A", @@ -133,7 +133,7 @@ static CURLcode test_unit1664(const char *arg) } { - static const char *single[] = { + static const char * const single[] = { "a", "aa", "A", @@ -156,7 +156,7 @@ static CURLcode test_unit1664(const char *arg) } { - static const char *single[] = { + static const char * const single[] = { "a", "aa", "A", @@ -177,7 +177,7 @@ static CURLcode test_unit1664(const char *arg) } { - static const char *nums[] = { + static const char * const nums[] = { "1", "10000", "1234", @@ -313,7 +313,7 @@ static CURLcode test_unit1664(const char *arg) { /* CURL_OFF_T is typically 9223372036854775807 */ - static const char *nums[] = { + static const char * const nums[] = { "9223372036854775807", /* 2^63 -1 */ "9223372036854775808", /* 2^63 */ "18446744073709551615", /* 2^64 - 1 */ @@ -347,7 +347,7 @@ static CURLcode test_unit1664(const char *arg) } { - static const char *newl[] = { + static const char * const newl[] = { "a", "aa", "A", @@ -372,7 +372,7 @@ static CURLcode test_unit1664(const char *arg) } { - static const char *nums[] = { + static const char * const nums[] = { "1", "1000", "1234", @@ -399,7 +399,7 @@ static CURLcode test_unit1664(const char *arg) } { - static const char *nums[] = { + static const char * const nums[] = { "1", "1000", "1234", @@ -427,7 +427,7 @@ static CURLcode test_unit1664(const char *arg) { /* CURL_OFF_T is typically 2^63-1 */ - static const char *nums[] = { + static const char * const nums[] = { "777777777777777777777", /* 2^63 -1 */ "1000000000000000000000", /* 2^63 */ "111111111111111111111", @@ -451,7 +451,7 @@ static CURLcode test_unit1664(const char *arg) { /* CURL_OFF_T is typically 2^63-1 */ - static const char *nums[] = { + static const char * const nums[] = { "7FFFFFFFFFFFFFFF", /* 2^63 -1 */ "8000000000000000", /* 2^63 */ "1111111111111111", diff --git a/tests/unit/unit1666.c b/tests/unit/unit1666.c index c2f20c977a..cf272da42f 100644 --- a/tests/unit/unit1666.c +++ b/tests/unit/unit1666.c @@ -36,7 +36,7 @@ struct test_1666 { }; /* the size of the object needs to deduct the null-terminator */ -#define OID(x) x, sizeof(x) - 1 +#define OID(x) STRCONST(x) static bool test1666(const struct test_1666 *spec, size_t i, struct dynbuf *dbuf) diff --git a/tests/unit/unit1675.c b/tests/unit/unit1675.c index 7e869651d0..1d7c44d461 100644 --- a/tests/unit/unit1675.c +++ b/tests/unit/unit1675.c @@ -38,7 +38,7 @@ static CURLcode test_unit1675(const char *arg) const char *in; const char *out; }; - const struct ipv4_test tests[] = { + static const struct ipv4_test tests[] = { { "0x.0x.0x.0x", NULL }, /* invalid hex */ { "0x.0x.0x", NULL }, /* invalid hex */ { "0x.0x", NULL }, /* invalid hex */ @@ -146,7 +146,7 @@ static CURLcode test_unit1675(const char *arg) unsigned int query; const char *out; }; - const struct urlencode_test tests[] = { + static const struct urlencode_test tests[] = { { "http://leave\x01/hello\x01world", FALSE, QUERY_NO, "http://leave\x01/hello%01world" }, { "http://leave/hello\x01world", FALSE, QUERY_NO, @@ -204,7 +204,7 @@ static CURLcode test_unit1675(const char *arg) const char *out_host; const char *out_zone; }; - const struct ipv6_test tests[] = { + static const struct ipv6_test tests[] = { { "[::1]", "[::1]", NULL }, { "[fe80::1%eth0]", "[fe80::1]", "eth0" }, { "[fe80::1%25eth0]", "[fe80::1]", "eth0" }, @@ -260,7 +260,7 @@ static CURLcode test_unit1675(const char *arg) const char *out_path; bool fine; }; - const struct file_test tests[] = { + static const struct file_test tests[] = { { "file:///etc/hosts", "/etc/hosts", TRUE }, { "file://localhost/etc/hosts", "/etc/hosts", TRUE }, { "file://apple/etc/hosts", "/etc/hosts", FALSE }, @@ -317,7 +317,7 @@ static CURLcode test_unit1675(const char *arg) const char *path; bool expect_match; }; - const struct origin_test tests[] = { + static const struct origin_test tests[] = { { "http://host:123/x", "http", "host", "123", "/y", TRUE }, { "http://host:123/x", NULL, "host", "123", "/y", TRUE }, { "http://host:123/x", NULL, NULL, NULL, "/y", TRUE }, @@ -395,7 +395,7 @@ loop_end: const char *options; size_t offset; }; - const struct test tests[] = { + static const struct test tests[] = { { CURLUE_OK, "foo:bar@host", NULL, 0, "foo", "bar", "o", 8 }, { CURLUE_OK, "foo:bar;abc@host", "imap", 0, "foo", "bar", "abc", 12 }, { CURLUE_OK, "foo:bar;abc@host", NULL, 0, "foo", "bar;abc", "o", 12 }, diff --git a/tests/unit/unit2603.c b/tests/unit/unit2603.c index 0198ccf7f4..f2ec4f6b90 100644 --- a/tests/unit/unit2603.c +++ b/tests/unit/unit2603.c @@ -48,7 +48,7 @@ static void check_eq(const char *s, const char *exp_s, const char *name) } struct tcase { - const char **input; + const char * const *input; const char *default_scheme; const char *custom_method; const char *method; @@ -117,7 +117,7 @@ static CURLcode test_unit2603(const char *arg) UNITTEST_BEGIN_SIMPLE #ifndef CURL_DISABLE_HTTP - static const char *T1_INPUT[] = { + static const char * const T1_INPUT[] = { "GET /path HTTP/1.1\r\nHost: test.curl.se\r\n\r\n", NULL, }; @@ -128,7 +128,7 @@ static CURLcode test_unit2603(const char *arg) T1_INPUT, "https", NULL, "GET", "https", NULL, "/path", 1, 0 }; - static const char *T2_INPUT[] = { + static const char * const T2_INPUT[] = { "GET /path HTT", "P/1.1\r\nHost: te", "st.curl.se\r\n\r", @@ -139,7 +139,7 @@ static CURLcode test_unit2603(const char *arg) T2_INPUT, NULL, NULL, "GET", NULL, NULL, "/path", 1, 8 }; - static const char *T3_INPUT[] = { + static const char * const T3_INPUT[] = { "GET ftp://ftp.curl.se/xxx?a=2 HTTP/1.1\r\nContent-Length: 0\r", "\nUser-Agent: xxx\r\n\r\n", NULL, @@ -148,7 +148,7 @@ static CURLcode test_unit2603(const char *arg) T3_INPUT, NULL, NULL, "GET", "ftp", "ftp.curl.se", "/xxx?a=2", 2, 0 }; - static const char *T4_INPUT[] = { + static const char * const T4_INPUT[] = { "CONNECT ftp.curl.se:123 HTTP/1.1\r\nContent-Length: 0\r\n", "User-Agent: xxx\r\n", "nothing: \r\n\r\n\n\n", @@ -158,7 +158,7 @@ static CURLcode test_unit2603(const char *arg) T4_INPUT, NULL, NULL, "CONNECT", NULL, "ftp.curl.se:123", NULL, 3, 2 }; - static const char *T6_INPUT[] = { + static const char * const T6_INPUT[] = { "PUT /path HTTP/1.1\nHost: test.curl.se\n\n123", NULL, }; @@ -167,7 +167,7 @@ static CURLcode test_unit2603(const char *arg) }; /* test a custom method with space, #19543 */ - static const char *T7_INPUT[] = { + static const char * const T7_INPUT[] = { "IN SANE /path HTTP/1.1\r\nContent-Length: 0\r\n\r\n", NULL, }; diff --git a/tests/unit/unit3200.c b/tests/unit/unit3200.c index 3a7a37597c..23e5d56713 100644 --- a/tests/unit/unit3200.c +++ b/tests/unit/unit3200.c @@ -45,7 +45,7 @@ static CURLcode test_unit3200(const char *arg) #define C1024 C256 C256 C256 C256 #define C4096 C1024 C1024 C1024 C1024 - static const char *filecontents[] = { + static const char * const filecontents[] = { /* Both should be read */ "LINE1\n" "LINE2 NEWLINE\n", diff --git a/tests/unit/unit3205.c b/tests/unit/unit3205.c index 039b679d0a..234d8ae933 100644 --- a/tests/unit/unit3205.c +++ b/tests/unit/unit3205.c @@ -420,7 +420,7 @@ static CURLcode test_unit3205(const char *arg) #endif }; - static const char *cs_test_string = + static const char cs_test_string[] = "TLS_AES_128_GCM_SHA256:TLS_AES_256_GCM_SHA384:" "TLS_CHACHA20_POLY1305_SHA256:ECDHE-ECDSA-AES128-GCM-SHA256:" "ECDHE-RSA-AES128-GCM-SHA256:ECDHE-ECDSA-AES256-GCM-SHA384:" @@ -561,11 +561,12 @@ static CURLcode test_unit3205(const char *arg) if(test->id >= 0x0011 && test->id < 0x0017) { if(expect && !memcmp(expect, "EDH-", 4)) { curlx_strcopy(alt, sizeof(alt), expect, strlen(expect)); - expect = (const char *)memcpy(alt, "DHE-", sizeof("DHE-") - 1); + expect = memcpy(alt, "DHE-", CURL_CSTRLEN("DHE-")); } if(expect && !memcmp(expect + 4, "EDH-", 4)) { curlx_strcopy(alt, sizeof(alt), expect, strlen(expect)); - expect = (const char *)memcpy(alt + 4, "DHE-", sizeof("DHE-") - 1) - 4; + expect = memcpy(alt + 4, "DHE-", CURL_CSTRLEN("DHE-")); + expect -= 4; } } diff --git a/tests/unit/unit3400.c b/tests/unit/unit3400.c index 060cc61799..364a2b540f 100644 --- a/tests/unit/unit3400.c +++ b/tests/unit/unit3400.c @@ -56,13 +56,13 @@ static void check_capsule_hdr(size_t payload_len, static void test_capsule_encap_udp_hdr_boundaries(void) { - const unsigned char p0[] = { 0x00, 0x01, 0x00 }; - const unsigned char p62[] = { 0x00, 0x3F, 0x00 }; - const unsigned char p63[] = { 0x00, 0x40, 0x40, 0x00 }; - const unsigned char p64[] = { 0x00, 0x40, 0x41, 0x00 }; - const unsigned char p16382[] = { 0x00, 0x7F, 0xFF, 0x00 }; - const unsigned char p16383[] = { 0x00, 0x80, 0x00, 0x40, 0x00, 0x00 }; - const unsigned char p16384[] = { 0x00, 0x80, 0x00, 0x40, 0x01, 0x00 }; + static const unsigned char p0[] = { 0x00, 0x01, 0x00 }; + static const unsigned char p62[] = { 0x00, 0x3F, 0x00 }; + static const unsigned char p63[] = { 0x00, 0x40, 0x40, 0x00 }; + static const unsigned char p64[] = { 0x00, 0x40, 0x41, 0x00 }; + static const unsigned char p16382[] = { 0x00, 0x7F, 0xFF, 0x00 }; + static const unsigned char p16383[] = { 0x00, 0x80, 0x00, 0x40, 0x00, 0x00 }; + static const unsigned char p16384[] = { 0x00, 0x80, 0x00, 0x40, 0x01, 0x00 }; check_capsule_hdr(0, p0, sizeof(p0)); check_capsule_hdr(62, p62, sizeof(p62)); @@ -139,7 +139,7 @@ static void test_capsule_sequential_decode(void) CURLcode err; size_t nread; /* Two back-to-back 3-byte UDP capsules */ - const unsigned char two_caps[] = { + static const unsigned char two_caps[] = { 0x00, 0x04, 0x00, 0x11, 0x22, 0x33, /* capsule 1: [0x11,0x22,0x33] */ 0x00, 0x04, 0x00, 0xAA, 0xBB, 0xCC /* capsule 2: [0xAA,0xBB,0xCC] */ }; @@ -186,13 +186,15 @@ static void test_capsule_decode_paths(void) unsigned char out[8]; CURLcode err = CURLE_OK; size_t nread; - const unsigned char invalid_type[] = { 0x01 }; - const unsigned char partial_len[] = { 0x00, 0x40 }; - const unsigned char invalid_context[] = { 0x00, 0x01, 0x01 }; - const unsigned char invalid_caps_len[] = { 0x00, 0x00, 0x00 }; - const unsigned char partial_payload[] = { 0x00, 0x04, 0x00, 0x11, 0x22 }; - const unsigned char payload_3b[] = { 0x00, 0x04, 0x00, 0x11, 0x22, 0x33 }; - const unsigned char payload_empty[] = { 0x00, 0x01, 0x00 }; + static const unsigned char invalid_type[] = { 0x01 }; + static const unsigned char partial_len[] = { 0x00, 0x40 }; + static const unsigned char invalid_context[] = { 0x00, 0x01, 0x01 }; + static const unsigned char invalid_caps_len[] = { 0x00, 0x00, 0x00 }; + static const unsigned char partial_payload[] = { 0x00, 0x04, 0x00, 0x11, + 0x22 }; + static const unsigned char payload_3b[] = { 0x00, 0x04, 0x00, + 0x11, 0x22, 0x33 }; + static const unsigned char payload_empty[] = { 0x00, 0x01, 0x00 }; Curl_bufq_init2(&q, 32, 4, BUFQ_OPT_NONE); From c39193a589164a5ef506385f352b9c904d7107f9 Mon Sep 17 00:00:00 2001 From: Dan Fandrich Date: Sat, 25 Jul 2026 13:06:38 -0700 Subject: [PATCH 07/15] tests: improve exception handling in Python test code * Explicitly set "check" in subprocess.run() to raise an exception automatically, where it was done manually before * Use contextlib.suppress to ignore exceptions * Use custom exceptions for test errors for clarity and flexibility. * Replace IOError with OSError This fixes ruff rules BLE001, PLW1510, S110, TRY201, TRY203, TRY002, UP024. --- tests/dictserver.py | 4 +- tests/http/scorecard.py | 6 +-- tests/http/test_05_errors.py | 7 ++- tests/http/test_11_unix.py | 4 +- tests/http/testenv/caddy.py | 2 +- tests/http/testenv/certs.py | 12 ++--- tests/http/testenv/client.py | 2 +- tests/http/testenv/curl.py | 67 +++++++++++----------------- tests/http/testenv/env.py | 39 ++++++++-------- tests/http/testenv/httpd.py | 16 +++---- tests/http/testenv/ports.py | 11 ++--- tests/http/testenv/sshd.py | 18 +++----- tests/http/testenv/ws_echo_server.py | 7 ++- tests/negtelnetserver.py | 4 +- tests/util.py | 2 +- 15 files changed, 86 insertions(+), 115 deletions(-) diff --git a/tests/dictserver.py b/tests/dictserver.py index b4e1afd78b..4419e11582 100755 --- a/tests/dictserver.py +++ b/tests/dictserver.py @@ -101,8 +101,8 @@ class DictHandler(socketserver.BaseRequestHandler): log.debug("[DICT] Responding with %r", response) self.request.sendall(response.encode("utf-8")) - except IOError: - log.exception("[DICT] IOError hit during request") + except OSError: + log.exception("[DICT] OSError hit during request") def get_options(): diff --git a/tests/http/scorecard.py b/tests/http/scorecard.py index 5bc24cf2c9..95e092672e 100644 --- a/tests/http/scorecard.py +++ b/tests/http/scorecard.py @@ -148,7 +148,7 @@ class Card: def parse_size(cls, s): m = re.match(r'(\d+)(mb|kb|gb)?', s, re.IGNORECASE) if m is None: - raise Exception(f'unrecognized size: {s}') + raise ScoreCardError(f'unrecognized size: {s}') size = int(m.group(1)) if not m.group(2): pass @@ -263,7 +263,7 @@ class ScoreRunner: if self._limit_rate: m = re.match(r'(\d+(\.\d+)?)([gmkb])?', self._limit_rate.lower()) if not m: - raise Exception(f'unrecognised limit-rate: {self._limit_rate}') + raise ScoreCardError(f'unrecognised limit-rate: {self._limit_rate}') self._limit_rate_num = float(m.group(1)) if m.group(3) == 'g': self._limit_rate_num *= 1024 * 1024 * 1024 @@ -274,7 +274,7 @@ class ScoreRunner: elif m.group(3) == 'b': pass else: - raise Exception(f'unrecognised limit-rate: {self._limit_rate}') + raise ScoreCardError(f'unrecognised limit-rate: {self._limit_rate}') self.suppress_cl = suppress_cl def info(self, msg): diff --git a/tests/http/test_05_errors.py b/tests/http/test_05_errors.py index 76c12bc8e5..60a9aaa2e4 100644 --- a/tests/http/test_05_errors.py +++ b/tests/http/test_05_errors.py @@ -24,6 +24,7 @@ # ########################################################################### # +import contextlib import logging import os import socket @@ -192,13 +193,11 @@ class TestErrors: # accept one connection and immediately close it def accept_and_close(): - try: + # ignore expected socket error + with contextlib.suppress(OSError): conn, _ = server.accept() conn.recv(1) # wait for ClientHello conn.close() - except Exception: - # ignore expected socket error - pass t = threading.Thread(target=accept_and_close) t.start() diff --git a/tests/http/test_11_unix.py b/tests/http/test_11_unix.py index 774a7737c9..b4e5ac7974 100644 --- a/tests/http/test_11_unix.py +++ b/tests/http/test_11_unix.py @@ -82,9 +82,7 @@ Content-Length: 19 finally: c.close() - except ConnectionAbortedError: - self._done = True - except OSError: + except (ConnectionAbortedError, OSError): self._done = True diff --git a/tests/http/testenv/caddy.py b/tests/http/testenv/caddy.py index 1d554b1906..a6c8b58c5c 100644 --- a/tests/http/testenv/caddy.py +++ b/tests/http/testenv/caddy.py @@ -125,7 +125,7 @@ class Caddy: self._process.terminate() try: self._process.wait(timeout=1) - except Exception: + except subprocess.TimeoutExpired: self._process.kill() self._process = None self.close_log() diff --git a/tests/http/testenv/certs.py b/tests/http/testenv/certs.py index 85012634a5..8c25155b24 100644 --- a/tests/http/testenv/certs.py +++ b/tests/http/testenv/certs.py @@ -57,6 +57,10 @@ EC_SUPPORTED.update([(curve.name.upper(), curve) for curve in [ ]]) +class CertError(Exception): + """Error in certificate handling.""" + + def _private_key(key_type): if isinstance(key_type, str): key_type = key_type.upper() @@ -150,7 +154,7 @@ class Credentials: return f"rsa{self._pkey.key_size}" if isinstance(self._pkey, EllipticCurvePrivateKey): return f"{self._pkey.curve.name}" - raise Exception(f"unknown key type: {self._pkey}") + raise CertError(f"unknown key type: {self._pkey}") @property def private_key(self) -> Any: @@ -249,9 +253,7 @@ class Credentials: os.makedirs(self.hashdir, exist_ok=True) p = subprocess.run(args=[ openssl, 'x509', '-hash', '-noout', '-in', self.cert_file - ], capture_output=True, text=True) - if p.returncode != 0: - raise Exception(f'openssl failed to compute cert hash: {p}') + ], capture_output=True, text=True, check=True) cert_hname = f'{p.stdout.strip()}.0' shutil.copy(self.cert_file, os.path.join(self.hashdir, cert_hname)) @@ -401,7 +403,7 @@ class TestCA: valid_from=valid_from, valid_to=valid_to, key_type=key_type) else: - raise Exception(f"unrecognized certificate specification: {spec}") + raise CertError(f"unrecognized certificate specification: {spec}") return creds @staticmethod diff --git a/tests/http/testenv/client.py b/tests/http/testenv/client.py index 76c4822cbc..0df19e5b42 100644 --- a/tests/http/testenv/client.py +++ b/tests/http/testenv/client.py @@ -98,7 +98,7 @@ class LocalClient: p = subprocess.run(myargs, stderr=cerr, stdout=cout, cwd=self._run_dir, shell=False, input=None, env=run_env, - timeout=self._timeout) + timeout=self._timeout, check=False) exitcode = p.returncode except subprocess.TimeoutExpired: log.warning(f'Timeout after {self._timeout}s: {args}') diff --git a/tests/http/testenv/curl.py b/tests/http/testenv/curl.py index 2abbbbe49c..8e187039ab 100644 --- a/tests/http/testenv/curl.py +++ b/tests/http/testenv/curl.py @@ -24,6 +24,7 @@ # ########################################################################### # +import contextlib import json import logging import os @@ -41,7 +42,7 @@ from urllib.parse import urlparse import psutil -from .env import Env +from .env import Env, EnvError log = logging.getLogger(__name__) @@ -133,12 +134,9 @@ class PerfProfile: self._proc.terminate() self._rc = self._proc.returncode with open(self._file, 'w') as cout: - p = subprocess.run([ + subprocess.run([ 'sudo', 'perf', 'script' - ], stdout=cout, cwd=self._run_dir, shell=False) - rc = p.returncode - if rc != 0: - raise Exception(f'perf returned error {rc}') + ], stdout=cout, cwd=self._run_dir, shell=False, check=True) @property def file(self): @@ -192,7 +190,7 @@ class RunTcpDump: port_pairs: Optional[List[Tuple[int, int]]] = None ) -> Optional[List[str]]: if self._proc: - raise Exception('tcpdump still running') + raise EnvError('tcpdump still running') # a pair matches only a RST between exactly these two ports, while # a port in `ports` matches any RST it is involved in pairs = None @@ -222,7 +220,7 @@ class RunTcpDump: @property def stderr(self) -> List[str]: if self._proc: - raise Exception('tcpdump still running') + raise EnvError('tcpdump still running') with open(self._stderrfile) as fd: return fd.readlines() @@ -232,7 +230,7 @@ class RunTcpDump: try: tcpdump = self._env.tcpdump() if tcpdump is None: - raise Exception('tcpdump not available') + raise EnvError('tcpdump not available') # look with tcpdump for TCP RST packets which indicate # we did not shut down connections cleanly args = [] @@ -249,11 +247,9 @@ class RunTcpDump: assert self._proc assert self._proc.returncode is None while self._proc: - try: + # timeout means tcpdump is still running + with contextlib.suppress(subprocess.TimeoutExpired): self._proc.wait(timeout=1) - except subprocess.TimeoutExpired: - # timeout means tcpdump is still running - pass except Exception: log.exception('Tcpdump') @@ -649,13 +645,13 @@ class CurlClient: if 'FLAMEGRAPH' in os.environ: self._fg_dir = os.environ['FLAMEGRAPH'] if not os.path.exists(self._fg_dir): - raise Exception(f'FlameGraph checkout not found in {self._fg_dir}, set env variable FLAMEGRAPH') + raise EnvError(f'FlameGraph checkout not found in {self._fg_dir}, set env variable FLAMEGRAPH') if sys.platform.startswith('linux'): self._with_perf = True elif sys.platform.startswith('darwin'): self._with_dtrace = True else: - raise Exception(f'flame graphs unsupported on {sys.platform}') + raise EnvError(f'flame graphs unsupported on {sys.platform}') self._socks_args = socks_args self._silent = silent self._run_env = run_env @@ -919,7 +915,7 @@ class CurlClient: '--upload-file', '-' ]) else: - raise Exception('need either file or data to upload') + raise EnvError('need either file or data to upload') if with_stats: extra_args.extend([ '-w', '%{json}\\n' @@ -995,7 +991,7 @@ class CurlClient: '--upload-file', '-' ]) else: - raise Exception('need either file or data to upload') + raise EnvError('need either file or data to upload') if with_stats: extra_args.extend([ '-w', '%{json}\\n' @@ -1071,7 +1067,7 @@ class CurlClient: cwd=self._run_dir, shell=False, input=intext.encode() if intext else None, timeout=self._timeout, - env=self._run_env) + env=self._run_env, check=False) exitcode = p.returncode except subprocess.TimeoutExpired: now = datetime.now() @@ -1160,7 +1156,7 @@ class CurlClient: args.extend(options) if alpn_proto is not None: if alpn_proto not in self.ALPN_ARG: - raise Exception(f'unknown ALPN protocol: "{alpn_proto}"') + raise EnvError(f'unknown ALPN protocol: "{alpn_proto}"') args.append(self.ALPN_ARG[alpn_proto]) if u.scheme == 'http': @@ -1243,36 +1239,30 @@ class CurlClient: def _perf_collapse(self, perf: PerfProfile, file_err): if not os.path.exists(perf.file): - raise Exception(f'perf output file does not exist: {perf.file}') + raise EnvError(f'perf output file does not exist: {perf.file}') fg_collapse = os.path.join(self._fg_dir, 'stackcollapse-perf.pl') if not os.path.exists(fg_collapse): - raise Exception(f'FlameGraph script not found: {fg_collapse}') + raise EnvError(f'FlameGraph script not found: {fg_collapse}') stacks_collapsed = f'{perf.file}.collapsed' log.info(f'collapsing stacks into {stacks_collapsed}') with open(stacks_collapsed, 'w') as cout, open(file_err, 'w') as cerr: - p = subprocess.run([ + subprocess.run([ fg_collapse, perf.file - ], stdout=cout, stderr=cerr, cwd=self._run_dir, shell=False) - rc = p.returncode - if rc != 0: - raise Exception(f'{fg_collapse} returned error {rc}') + ], stdout=cout, stderr=cerr, cwd=self._run_dir, shell=False, check=True) return stacks_collapsed def _dtrace_collapse(self, dtrace: DTraceProfile, file_err): if not os.path.exists(dtrace.file): - raise Exception(f'dtrace output file does not exist: {dtrace.file}') + raise EnvError(f'dtrace output file does not exist: {dtrace.file}') fg_collapse = os.path.join(self._fg_dir, 'stackcollapse.pl') if not os.path.exists(fg_collapse): - raise Exception(f'FlameGraph script not found: {fg_collapse}') + raise EnvError(f'FlameGraph script not found: {fg_collapse}') stacks_collapsed = f'{dtrace.file}.collapsed' log.info(f'collapsing stacks into {stacks_collapsed}') with open(stacks_collapsed, 'w') as cout, open(file_err, 'a') as cerr: - p = subprocess.run([ + subprocess.run([ fg_collapse, dtrace.file - ], stdout=cout, stderr=cerr, cwd=self._run_dir, shell=False) - rc = p.returncode - if rc != 0: - raise Exception(f'{fg_collapse} returned error {rc}') + ], stdout=cout, stderr=cerr, cwd=self._run_dir, shell=False, check=True) return stacks_collapsed def _generate_flame(self, curl_args: List[str], @@ -1281,7 +1271,7 @@ class CurlClient: fg_gen_flame = os.path.join(self._fg_dir, 'flamegraph.pl') file_svg = os.path.join(self._run_dir, 'curl.flamegraph.svg') if not os.path.exists(fg_gen_flame): - raise Exception(f'FlameGraph script not found: {fg_gen_flame}') + raise EnvError(f'FlameGraph script not found: {fg_gen_flame}') log.info('waiting a sec for perf/dtrace to finish flushing') time.sleep(2) @@ -1292,7 +1282,7 @@ class CurlClient: elif dtrace: stacks_collapsed = self._dtrace_collapse(dtrace, file_err) else: - raise Exception('no stacks measure given') + raise EnvError('no stacks measure given') log.info(f'generating graph into {file_svg}') cmdline = ' '.join(curl_args) @@ -1303,14 +1293,11 @@ class CurlClient: title = cmdline subtitle = '' with open(file_svg, 'w') as cout, open(file_err, 'a') as cerr: - p = subprocess.run([ + subprocess.run([ fg_gen_flame, '--colors', 'green', '--title', title, '--subtitle', subtitle, stacks_collapsed - ], stdout=cout, stderr=cerr, cwd=self._run_dir, shell=False) - rc = p.returncode - if rc != 0: - raise Exception(f'{fg_gen_flame} returned error {rc}') + ], stdout=cout, stderr=cerr, cwd=self._run_dir, shell=False, check=True) def mk_altsvc_file(self, name, src_alpn, src_host, src_port, dest_alpn, dest_host, dest_port): diff --git a/tests/http/testenv/env.py b/tests/http/testenv/env.py index 8f619271a2..5acb3ab67a 100644 --- a/tests/http/testenv/env.py +++ b/tests/http/testenv/env.py @@ -43,6 +43,10 @@ from .certs import CertificateSpec, Credentials, TestCA log = logging.getLogger(__name__) +class EnvError(Exception): + """Exception from the test environment.""" + + def init_config_from(conf_path): if os.path.isfile(conf_path): config = ConfigParser(interpolation=ExtendedInterpolation()) @@ -58,7 +62,7 @@ CONFIG_PATH = os.path.join(TOP_PATH, "tests", "http", "config.ini") if not os.path.exists(CONFIG_PATH): ALT_CONFIG_PATH = os.path.join(PROJ_PATH, "tests", "http", "config.ini") if not os.path.exists(ALT_CONFIG_PATH): - raise Exception( + raise EnvError( f"unable to find config.ini in {CONFIG_PATH} nor {ALT_CONFIG_PATH}" ) TOP_PATH = PROJ_PATH @@ -77,11 +81,7 @@ class NghttpxUtil: if cmd is None: return None if cls.VERSION_FULL is None or cmd != cls.CMD: - p = subprocess.run(args=[cmd, "--version"], capture_output=True, text=True) - if p.returncode != 0: - raise RuntimeError( - f"{cmd} --version failed with exit code: {p.returncode}" - ) + p = subprocess.run(args=[cmd, "--version"], capture_output=True, text=True, check=True) cls.CMD = cmd for line in p.stdout.splitlines(keepends=False): if line.startswith("nghttpx "): @@ -131,9 +131,7 @@ class EnvConfig: } self.curl_is_debug = False self.curl_protos = [] - p = subprocess.run(args=[self.curl, "-V"], capture_output=True, text=True) - if p.returncode != 0: - raise RuntimeError(f"{self.curl} -V failed with exit code: {p.returncode}") + p = subprocess.run(args=[self.curl, "-V"], capture_output=True, text=True, check=True) if p.stderr.startswith("WARNING:"): self.curl_is_debug = True for line in p.stdout.splitlines(keepends=False): @@ -162,9 +160,7 @@ class EnvConfig: prot.lower() for prot in line[11:].split(" ") } - p = subprocess.run(args=[self.curlinfo], capture_output=True, text=True) - if p.returncode != 0: - raise RuntimeError(f"{self.curlinfo} failed with exit code: {p.returncode}") + p = subprocess.run(args=[self.curlinfo], capture_output=True, text=True, check=True) self.curl_is_verbose = 'verbose-strings: ON' in p.stdout self.curl_can_cert_status = 'cert-status: ON' in p.stdout self.curl_override_dns = 'override-dns: ON' in p.stdout @@ -226,7 +222,7 @@ class EnvConfig: self.openssl = "openssl" p = subprocess.run( - args=[self.openssl, "version"], capture_output=True, text=True + args=[self.openssl, "version"], capture_output=True, text=True, check=False ) if p.returncode != 0: # no openssl in path @@ -256,7 +252,7 @@ class EnvConfig: if self.h2o is not None: try: p = subprocess.run( - args=[self.h2o, "--version"], capture_output=True, text=True + args=[self.h2o, "--version"], capture_output=True, text=True, check=False ) if p.returncode != 0: # not a working h2o @@ -274,7 +270,7 @@ class EnvConfig: if self.caddy is not None: p = subprocess.run( - args=[self.caddy, "version"], capture_output=True, text=True + args=[self.caddy, "version"], capture_output=True, text=True, check=False ) if p.returncode != 0: # not a working caddy @@ -294,7 +290,7 @@ class EnvConfig: if self.vsftpd is not None: with tempfile.TemporaryFile("w+") as tmp: p = subprocess.run( - args=[self.vsftpd, "-v"], capture_output=True, text=True, stdin=tmp + args=[self.vsftpd, "-v"], capture_output=True, text=True, stdin=tmp, check=False ) if p.returncode != 0: # not a working vsftpd @@ -315,14 +311,14 @@ class EnvConfig: # vsftp does not use stdout or stderr for printing its version... -.- self._vsftpd_version = "unknown" else: - raise Exception(f"Unable to determine VsFTPD version from: {p.stderr}") + raise EnvError(f"Unable to determine VsFTPD version from: {p.stderr}") self.danted = self.config["danted"]["danted"] if self.danted == "": self.danted = None self._danted_version = None if self.danted is not None: - p = subprocess.run(args=[self.danted, "-v"], capture_output=True, text=True) + p = subprocess.run(args=[self.danted, "-v"], capture_output=True, text=True, check=False) assert p.returncode == 0 if p.returncode != 0: # not a working vsftpd @@ -334,14 +330,14 @@ class EnvConfig: self._danted_version = m.group(1) else: self.danted = None - raise Exception(f"Unable to determine danted version from: {p.stderr}") + raise EnvError(f"Unable to determine danted version from: {p.stderr}") self.sshd = self.config["sshd"]["sshd"] if self.sshd == "": self.sshd = None self._sshd_version = None if self.sshd is not None: - p = subprocess.run(args=[self.sshd, "-V"], capture_output=True, text=True) + p = subprocess.run(args=[self.sshd, "-V"], capture_output=True, text=True, check=False) assert p.returncode == 0 if p.returncode != 0: self.sshd = None @@ -352,7 +348,7 @@ class EnvConfig: self._sshd_version = m.group(1) else: self.sshd = None - raise Exception( + raise EnvError( f"Unable to determine sshd version from: {p.stderr}" ) @@ -373,6 +369,7 @@ class EnvConfig: args=[self.apxs, "-q", "HTTPD_VERSION"], capture_output=True, text=True, + check=False, ) if p.returncode != 0: log.error(f"{self.apxs} failed to query HTTPD_VERSION: {p}") diff --git a/tests/http/testenv/httpd.py b/tests/http/testenv/httpd.py index 64ca796d13..10ccce0c4a 100644 --- a/tests/http/testenv/httpd.py +++ b/tests/http/testenv/httpd.py @@ -37,7 +37,7 @@ from json import JSONEncoder from typing import Dict, List, Optional, Union from .curl import CurlClient, ExecResult -from .env import Env +from .env import Env, EnvError from .ports import alloc_ports_and_do log = logging.getLogger(__name__) @@ -95,14 +95,12 @@ class Httpd: self._loaded_domain1_cred_name = None assert env.apxs p = subprocess.run(args=[env.apxs, '-q', 'libexecdir'], - capture_output=True, text=True) - if p.returncode != 0: - raise Exception(f'{env.apxs} failed to query libexecdir: {p}') + capture_output=True, text=True, check=True) self._mods_dir = p.stdout.strip() if self._mods_dir is None: - raise Exception('apache modules directory cannot be found') + raise EnvError('apache modules directory cannot be found') if not os.path.exists(self._mods_dir): - raise Exception(f'apache modules directory does not exist: {self._mods_dir}') + raise EnvError(f'apache modules directory does not exist: {self._mods_dir}') self._maybe_running = False self.ports = {} self._rmf(self._error_log) @@ -144,7 +142,7 @@ class Httpd: p = subprocess.run(args, stderr=subprocess.PIPE, stdout=subprocess.PIPE, cwd=self.env.gen_dir, input=intext.encode() if intext else None, - env=env) + env=env, check=True) start = datetime.now() return ExecResult(args=args, exit_code=p.returncode, stdout=p.stdout.decode().splitlines(), @@ -587,9 +585,9 @@ class Httpd: shutil.copy(in_source, out_source) p = subprocess.run([ self.env.apxs, '-c', out_source - ], capture_output=True, cwd=out_dir) + ], capture_output=True, cwd=out_dir, check=False) rv = p.returncode if rv != 0: log.error(f"compiling mod_curltest failed: {p.stderr}") - raise Exception(f"compiling mod_curltest failed: {p.stderr}") + raise EnvError(f"compiling mod_curltest failed: {p.stderr}") Httpd.MOD_CURLTEST = os.path.join(out_dir, '.libs/mod_curltest.so') diff --git a/tests/http/testenv/ports.py b/tests/http/testenv/ports.py index f3d2348fa6..10accb2f3b 100644 --- a/tests/http/testenv/ports.py +++ b/tests/http/testenv/ports.py @@ -39,13 +39,10 @@ def alloc_port_set(port_specs: Dict[str, int]) -> Dict[str, int]: socks = [] ports = {} for name, ptype in port_specs.items(): - try: - s = socket.socket(type=ptype) - s.bind(('127.0.0.1', 0)) - ports[name] = s.getsockname()[1] - socks.append(s) - except Exception as e: - raise e + s = socket.socket(type=ptype) + s.bind(('127.0.0.1', 0)) + ports[name] = s.getsockname()[1] + socks.append(s) for s in socks: s.close() return ports diff --git a/tests/http/testenv/sshd.py b/tests/http/testenv/sshd.py index de8078dd26..49c39ce494 100644 --- a/tests/http/testenv/sshd.py +++ b/tests/http/testenv/sshd.py @@ -125,11 +125,9 @@ class Sshd: for alg in self._key_algs: key_file = os.path.join(self._sshd_dir, f'ssh_host_{alg}_key') if not os.path.exists(key_file): - p = subprocess.run(args=[ + subprocess.run(args=[ self._keygen, '-q', '-N', '', '-t', alg, '-f', key_file - ], capture_output=True, text=True) - if p.returncode != 0: - raise RuntimeError(f'error generating host key {key_file}: {p.returncode}') + ], capture_output=True, text=True, check=True) self._host_key_files.append(key_file) pub_file = f'{key_file}.pub' self._host_pub_files.append(pub_file) @@ -139,11 +137,9 @@ class Sshd: fd_known.write(f'[{self.env.domain1.lower()}]:{self.port} {pubkey}') fd_unknown.write(f'dummy.invalid {pubkey}') # hash the known_hosts file, libssh requires it - p = subprocess.run(args=[ + subprocess.run(args=[ self._keygen, '-H', '-f', self._known_hosts - ], capture_output=True, text=True) - if p.returncode != 0: - raise RuntimeError(f'error hashing {self._known_hosts}: {p.returncode}') + ], capture_output=True, text=True, check=True) def mk_user_keys(self): self._user_key_files = [] @@ -152,11 +148,9 @@ class Sshd: for user in self._users: key_file = os.path.join(self._sshd_dir, f'id_{user}_user_{alg}_key') if not os.path.exists(key_file): - p = subprocess.run(args=[ + subprocess.run(args=[ self._keygen, '-q', '-N', '', '-t', alg, '-f', key_file - ], capture_output=True, text=True) - if p.returncode != 0: - raise RuntimeError(f'error generating user key {key_file}: {p.returncode}') + ], capture_output=True, text=True, check=True) self._user_key_files.append(key_file) self._user_pub_files.append(f'{key_file}.pub') with open(self._auth_keys, 'w') as fd: diff --git a/tests/http/testenv/ws_echo_server.py b/tests/http/testenv/ws_echo_server.py index f3f659a27f..fddd26f271 100755 --- a/tests/http/testenv/ws_echo_server.py +++ b/tests/http/testenv/ws_echo_server.py @@ -26,6 +26,7 @@ # import argparse import asyncio +import contextlib import logging from websockets import server @@ -33,12 +34,10 @@ from websockets.exceptions import ConnectionClosedError async def echo(websocket): - try: + # exception when websocket connection closed by client + with contextlib.suppress(ConnectionClosedError): async for message in websocket: await websocket.send(message) - except ConnectionClosedError: - # websocket connection closed by client - pass async def run_server(port): diff --git a/tests/negtelnetserver.py b/tests/negtelnetserver.py index a9a4880018..a65b156630 100755 --- a/tests/negtelnetserver.py +++ b/tests/negtelnetserver.py @@ -109,8 +109,8 @@ class NegotiatingTelnetHandler(socketserver.BaseRequestHandler): self.request.recv(4 * 1024) self.request.shutdown(socket.SHUT_RDWR) - except IOError: - log.exception("IOError hit during request") + except OSError: + log.exception("OSError hit during request") class Negotiator: diff --git a/tests/util.py b/tests/util.py index 7db47d0a00..2921e93aa8 100755 --- a/tests/util.py +++ b/tests/util.py @@ -77,7 +77,7 @@ class TestData: m = REPLY_DATA.search(contents) if not m: - raise Exception("Could not find a section") + raise RuntimeError("Could not find a section") # Left-strip the data so we do not get a newline before our data. return m.group(1).lstrip() From 4eb691e89c3e324d10d112510bb76f352d655b64 Mon Sep 17 00:00:00 2001 From: Dan Fandrich Date: Sat, 25 Jul 2026 13:35:51 -0700 Subject: [PATCH 08/15] tests: change whitespace and comments in Python test code * remove an unneeded ruff warning disable * remove coding: utf-8 from Python code; PEP 3120 makes UTF-8 the default encoding * remove unusable shebang lines from Python code * remove empty print strings * disable warnings when file objects are stored; these instances can't be handled with context managers * use more consistent whitespace in Python code, fixing flake8 warnings * set the executable bit on scorecard.py, making it easier to run These fix ruff rules EXE001, FURB105, UP009, SIM115. --- tests/dictserver.py | 1 - tests/ech_combos.py | 9 ++-- tests/http/scorecard.py | 23 +++++----- tests/http/test_01_basic.py | 2 - tests/http/test_02_download.py | 10 ++-- tests/http/test_03_goaway.py | 2 - tests/http/test_04_stuttered.py | 2 - tests/http/test_05_errors.py | 2 - tests/http/test_06_eyeballs.py | 4 +- tests/http/test_07_upload.py | 12 ++--- tests/http/test_08_caddy.py | 2 - tests/http/test_09_push.py | 2 - tests/http/test_10_proxy.py | 2 - tests/http/test_11_unix.py | 2 - tests/http/test_12_reuse.py | 2 - tests/http/test_13_proxy_auth.py | 6 +-- tests/http/test_14_auth.py | 6 +-- tests/http/test_15_tracing.py | 10 ++-- tests/http/test_16_info.py | 2 - tests/http/test_17_ssl_use.py | 6 +-- tests/http/test_18_methods.py | 2 - tests/http/test_19_shutdown.py | 2 - tests/http/test_20_websockets.py | 6 +-- tests/http/test_21_resolve.py | 16 +++---- tests/http/test_22_httpsrr.py | 2 - tests/http/test_30_vsftpd.py | 2 - tests/http/test_31_vsftpds.py | 6 +-- tests/http/test_32_ftps_vsftpd.py | 6 +-- tests/http/test_40_socks.py | 2 - tests/http/test_50_scp.py | 2 - tests/http/test_51_sftp.py | 2 - tests/http/test_60_h3_proxy.py | 2 - tests/http/testenv/__init__.py | 4 +- tests/http/testenv/caddy.py | 4 +- tests/http/testenv/certs.py | 2 - tests/http/testenv/client.py | 4 +- tests/http/testenv/curl.py | 61 +++++++++++-------------- tests/http/testenv/dante.py | 8 ++-- tests/http/testenv/dnsd.py | 4 +- tests/http/testenv/env.py | 12 ++--- tests/http/testenv/h2o.py | 4 +- tests/http/testenv/httpd.py | 7 +-- tests/http/testenv/nghttpx.py | 6 +-- tests/http/testenv/ports.py | 2 - tests/http/testenv/sshd.py | 4 +- tests/http/testenv/vsftpd.py | 4 +- tests/http/testenv/ws_4frames_server.py | 1 - tests/http/testenv/ws_echo_server.py | 1 - tests/negtelnetserver.py | 1 - tests/smbserver.py | 17 +++---- tests/util.py | 1 - 51 files changed, 105 insertions(+), 199 deletions(-) mode change 100644 => 100755 tests/http/scorecard.py diff --git a/tests/dictserver.py b/tests/dictserver.py index 4419e11582..ea9f586c44 100755 --- a/tests/dictserver.py +++ b/tests/dictserver.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | diff --git a/tests/ech_combos.py b/tests/ech_combos.py index 8b15eff41f..90db92ca91 100755 --- a/tests/ech_combos.py +++ b/tests/ech_combos.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | @@ -45,12 +44,12 @@ def CombinationRepetitionUtil(chosen, arr, badarr, index, if chosen[j] in badarr: res = 0 j = j - 1 - print("cli_test $turl 1", res, end = " ") + print("cli_test $turl 1", res, end=" ") # print combination but eliminating any runs of # two identical params for j in range(r): if j != 0 and chosen[j] != chosen[j-1]: - print(chosen[j], end = " ") + print(chosen[j], end=" ") print() return @@ -89,8 +88,8 @@ def CombinationRepetition(arr, badarr, n, r): # Driver code -badarr = [ '--ech grease', '--ech false', '--ech ecl:$badecl', '--ech pn:$badpn' ] -goodarr = [ '--ech hard', '--ech true', '--ech ecl:$goodecl', '--ech pn:$goodpn' ] +badarr = ['--ech grease', '--ech false', '--ech ecl:$badecl', '--ech pn:$badpn'] +goodarr = ['--ech hard', '--ech true', '--ech ecl:$goodecl', '--ech pn:$goodpn'] arr = badarr + goodarr r = 8 n = len(arr) - 1 diff --git a/tests/http/scorecard.py b/tests/http/scorecard.py old mode 100644 new mode 100755 index 95e092672e..1550ccb99e --- a/tests/http/scorecard.py +++ b/tests/http/scorecard.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | @@ -211,7 +210,7 @@ class Card: print(f' {col:>{colw[idx]}} {"[cpu/rss]":<{statw}}', end='') else: print(f' {col:>{colw[idx]}}', end='') - print('') + print() for row in rows: for idx, cell in enumerate(row): print(f' {cell["sval"]:>{colw[idx]}}', end='') @@ -224,7 +223,7 @@ class Card: print(f' {s:<{statw}}', end='') if 'errors' in cell: errors.extend(cell['errors']) - print('') + print() if len(errors): print(f'Errors: {errors}') @@ -647,13 +646,15 @@ class ScoreRunner: rows = [] mparallel = meta['request_parallels'] cols.extend([f'{mp} max' for mp in mparallel]) - row = [{ - 'val': fsize, - 'sval': Card.fmt_size(fsize) - },{ - 'val': count, - 'sval': f'{count}', - }] + row = [ + { + 'val': fsize, + 'sval': Card.fmt_size(fsize) + }, { + 'val': count, + 'sval': f'{count}', + } + ] self.info('requests, max parallel...') row.extend([self.do_requests(url=url, count=count, max_parallel=mp, nsamples=meta["samples"]) @@ -992,7 +993,7 @@ def main(): parser.add_argument("--remote", action='store', type=str, default=None, help="score against the remote server at :") parser.add_argument("--flame", action='store_true', - default = False, help="produce a flame graph on curl") + default=False, help="produce a flame graph on curl") parser.add_argument("--limit-rate", action='store', type=str, default=None, help="use curl's --limit-rate") parser.add_argument("--http-plain", action='store_true', diff --git a/tests/http/test_01_basic.py b/tests/http/test_01_basic.py index 86f7ad191f..24e03d19b8 100644 --- a/tests/http/test_01_basic.py +++ b/tests/http/test_01_basic.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | diff --git a/tests/http/test_02_download.py b/tests/http/test_02_download.py index 413d518a6e..437db80ae4 100644 --- a/tests/http/test_02_download.py +++ b/tests/http/test_02_download.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | @@ -141,8 +139,8 @@ class TestDownload: urln = f'https://{env.authority_for(env.domain1, proto)}/data.json?[0-{count-1}]' r = curl.http_download(urls=[urln], alpn_proto=proto, with_stats=True, extra_args=[ - '--parallel', '--parallel-max', '200' - ]) + '--parallel', '--parallel-max', '200' + ]) r.check_response(http_status=200, count=count) # should have used at most 2 connections only (test servers allow 100 req/conn) # it may be 1 on slow systems where request are answered faster than @@ -157,8 +155,8 @@ class TestDownload: urln = f'https://{env.authority_for(env.domain1, proto)}/data.json?[0-{count-1}]' r = curl.http_download(urls=[urln], alpn_proto=proto, with_stats=True, extra_args=[ - '--parallel' - ]) + '--parallel' + ]) r.check_response(count=count, http_status=200) # http/1.1 should have used count connections assert r.total_connects == count, "http/1.1 should use this many connections" diff --git a/tests/http/test_03_goaway.py b/tests/http/test_03_goaway.py index 4c57bf2715..36febdbd18 100644 --- a/tests/http/test_03_goaway.py +++ b/tests/http/test_03_goaway.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | diff --git a/tests/http/test_04_stuttered.py b/tests/http/test_04_stuttered.py index 1c578e2e9e..3ad25d93ae 100644 --- a/tests/http/test_04_stuttered.py +++ b/tests/http/test_04_stuttered.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | diff --git a/tests/http/test_05_errors.py b/tests/http/test_05_errors.py index 60a9aaa2e4..768416eea3 100644 --- a/tests/http/test_05_errors.py +++ b/tests/http/test_05_errors.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | diff --git a/tests/http/test_06_eyeballs.py b/tests/http/test_06_eyeballs.py index 1dc3726f48..b72a89d75e 100644 --- a/tests/http/test_06_eyeballs.py +++ b/tests/http/test_06_eyeballs.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | @@ -129,7 +127,7 @@ class TestEyeballs: assert r.stats[0]['time_connect'] == 0 # no one connected # check that we indeed started attempts on all 3 addresses tcp_attempts = [line for line in r.trace_lines - if re.match(r'.*Trying \[100::[123]]:443', line)] + if re.match(r'.*Trying \[100::[123]]:443', line)] assert len(tcp_attempts) == 3, f'fond: {"".join(tcp_attempts)}\n{r.dump_logs()}' # if the 0100::/64 really goes into the void, we should see 2 HAPPY_EYEBALLS # timeouts being set here diff --git a/tests/http/test_07_upload.py b/tests/http/test_07_upload.py index 6cb4d943e1..7ad396d73c 100644 --- a/tests/http/test_07_upload.py +++ b/tests/http/test_07_upload.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | @@ -549,7 +547,7 @@ class TestUpload: ]) r.check_exit_code(0) results = [int(m.group(1)) for line in r.trace_lines - if (m := re.match(r'.* FINISHED, result=(\d+), response=(\d+)', line))] + if (m := re.match(r'.* FINISHED, result=(\d+), response=(\d+)', line))] httpcodes = [int(m.group(2)) for line in r.trace_lines if (m := re.match(r'.* FINISHED, result=(\d+), response=(\d+)', line))] if httpcode == 308: @@ -568,8 +566,8 @@ class TestUpload: url = f'https://{env.authority_for(env.domain1, proto)}/curltest/put?id=[0-0]' r = curl.http_put(urls=[url], fdata=fdata, alpn_proto=proto, with_headers=True, extra_args=[ - '--limit-rate', f'{speed_limit}' - ]) + '--limit-rate', f'{speed_limit}' + ]) r.check_response(count=count, http_status=200) assert r.responses[0]['header']['received-length'] == f'{up_len}', f'{r.responses[0]}' up_speed = r.stats[0]['speed_upload'] @@ -585,8 +583,8 @@ class TestUpload: url = f'https://{env.authority_for(env.domain1, proto)}/curltest/echo?id=[0-0]' r = curl.http_upload(urls=[url], data=f'@{fdata}', alpn_proto=proto, with_headers=True, extra_args=[ - '--limit-rate', f'{speed_limit}' - ]) + '--limit-rate', f'{speed_limit}' + ]) r.check_response(count=count, http_status=200) up_speed = r.stats[0]['speed_upload'] assert up_speed <= (speed_limit * 1.1), f'{r.stats[0]}' diff --git a/tests/http/test_08_caddy.py b/tests/http/test_08_caddy.py index 23cea4582a..70413a84d5 100644 --- a/tests/http/test_08_caddy.py +++ b/tests/http/test_08_caddy.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | diff --git a/tests/http/test_09_push.py b/tests/http/test_09_push.py index 386289b39e..7fb37b679d 100644 --- a/tests/http/test_09_push.py +++ b/tests/http/test_09_push.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | diff --git a/tests/http/test_10_proxy.py b/tests/http/test_10_proxy.py index 7ef77465bc..bd07841a68 100644 --- a/tests/http/test_10_proxy.py +++ b/tests/http/test_10_proxy.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | diff --git a/tests/http/test_11_unix.py b/tests/http/test_11_unix.py index b4e5ac7974..6ba500e1ce 100644 --- a/tests/http/test_11_unix.py +++ b/tests/http/test_11_unix.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | diff --git a/tests/http/test_12_reuse.py b/tests/http/test_12_reuse.py index d4e2f70861..b7a2513ef0 100644 --- a/tests/http/test_12_reuse.py +++ b/tests/http/test_12_reuse.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | diff --git a/tests/http/test_13_proxy_auth.py b/tests/http/test_13_proxy_auth.py index 50e4596057..4e5d45e918 100644 --- a/tests/http/test_13_proxy_auth.py +++ b/tests/http/test_13_proxy_auth.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | @@ -175,9 +173,9 @@ class TestProxyAuth: url2 = f'http://localhost:{env.http_port}/data.json?2' url3 = f'http://localhost:{env.http_port}/data.json?3' xargs1 = curl.get_proxy_args(proxys=False, tunnel=True) - xargs1.extend(['--proxy-user', 'proxy:proxy']) # good auth + xargs1.extend(['--proxy-user', 'proxy:proxy']) # good auth xargs2 = curl.get_proxy_args(proxys=False, tunnel=True) - xargs2.extend(['--proxy-user', 'ungood:ungood']) # bad auth + xargs2.extend(['--proxy-user', 'ungood:ungood']) # bad auth xargs3 = curl.get_proxy_args(proxys=False, tunnel=True) # no auth r = curl.http_download(urls=[url1, url2, url3], alpn_proto='http/1.1', with_stats=True, diff --git a/tests/http/test_14_auth.py b/tests/http/test_14_auth.py index ca808e0077..268ebae514 100644 --- a/tests/http/test_14_auth.py +++ b/tests/http/test_14_auth.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | @@ -64,7 +62,7 @@ class TestAuth: def test_14_03_digest_put_auth(self, env: Env, httpd, nghttpx, proto): if not env.curl_has_feature('digest'): pytest.skip("curl built without digest") - data='0123456789' + data = '0123456789' curl = CurlClient(env=env) url = f'https://{env.authority_for(env.domain1, proto)}/restricted/digest/data.json' r = curl.http_upload(urls=[url], data=data, alpn_proto=proto, extra_args=[ @@ -77,7 +75,7 @@ class TestAuth: def test_14_04_digest_large_pw(self, env: Env, httpd, nghttpx, proto): if not env.curl_has_feature('digest'): pytest.skip("curl built without digest") - data='0123456789' + data = '0123456789' password = 'x' * 65535 curl = CurlClient(env=env) url = f'https://{env.authority_for(env.domain1, proto)}/restricted/digest/data.json' diff --git a/tests/http/test_15_tracing.py b/tests/http/test_15_tracing.py index d1bcc22273..d2e987f867 100644 --- a/tests/http/test_15_tracing.py +++ b/tests/http/test_15_tracing.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | @@ -55,7 +53,7 @@ class TestTracing: '-v', '--trace-config', 'ids' ]) r.check_response(http_status=200) - for line in r.trace_lines: + for line in r.trace_lines: m = re.match(r'^\[0-[0x]] .+', line) if m is None: assert False, f'no match: {line}' @@ -68,7 +66,7 @@ class TestTracing: '-v', '--trace-config', 'ids,time' ]) r.check_response(http_status=200) - for line in r.trace_lines: + for line in r.trace_lines: m = re.match(r'^([0-9:.]+) \[0-[0x]] .+', line) if m is None: assert False, f'no match: {line}' @@ -84,7 +82,7 @@ class TestTracing: ]) r.check_response(http_status=200) found_tcp = False - for line in r.trace_lines: + for line in r.trace_lines: m = re.match(r'^([0-9:.]+) \[0-[0x]] .+', line) if m is None: assert False, f'no match: {line}' @@ -102,7 +100,7 @@ class TestTracing: ]) r.check_response(http_status=200) found_tcp = False - for line in r.trace_lines: + for line in r.trace_lines: m = re.match(r'^\[0-[0x]] .+', line) if m is None: assert False, f'no match: {line}' diff --git a/tests/http/test_16_info.py b/tests/http/test_16_info.py index 977342eb55..0d184931e2 100644 --- a/tests/http/test_16_info.py +++ b/tests/http/test_16_info.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | diff --git a/tests/http/test_17_ssl_use.py b/tests/http/test_17_ssl_use.py index 4179925f42..c5b5e144f3 100644 --- a/tests/http/test_17_ssl_use.py +++ b/tests/http/test_17_ssl_use.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | @@ -222,7 +220,7 @@ class TestSSLUse: ['AES256ish', ['ECDHE-ECDSA-AES256-GCM-SHA384', 'ECDHE-RSA-AES256-GCM-SHA384'], False], ['CHACHA20ish', ['ECDHE-ECDSA-CHACHA20-POLY1305', 'ECDHE-RSA-CHACHA20-POLY1305'], True], ['AES256ish+CHACHA20ish', ['ECDHE-ECDSA-AES256-GCM-SHA384', 'ECDHE-RSA-AES256-GCM-SHA384', - 'ECDHE-ECDSA-CHACHA20-POLY1305', 'ECDHE-RSA-CHACHA20-POLY1305'], True], + 'ECDHE-ECDSA-CHACHA20-POLY1305', 'ECDHE-RSA-CHACHA20-POLY1305'], True], ] ret = [] for tls_id, tls_proto in { @@ -521,7 +519,7 @@ class TestSSLUse: pytest.param("-MAC-ALL:+AEAD", "TLSv1.3", ['TLS_CHACHA20_POLY1305_SHA256'], True, id='TLSv1.3-MAC-only-AEAD'), pytest.param("-GROUP-ALL:+GROUP-X25519", "TLSv1.3", ['TLS_CHACHA20_POLY1305_SHA256'], True, id='TLSv1.3-group-only-X25519'), pytest.param("-GROUP-ALL:+GROUP-SECP192R1", "", [], False, id='group-only-SECP192R1'), - ]) + ]) def test_17_18_gnutls_priority(self, env: Env, httpd, configures_httpd, priority, tls_proto, ciphers, success): # to test setting cipher suites, the AES 256 ciphers are disabled in the test server httpd.set_extra_config('base', [ diff --git a/tests/http/test_18_methods.py b/tests/http/test_18_methods.py index faa31a638e..452b422c6b 100644 --- a/tests/http/test_18_methods.py +++ b/tests/http/test_18_methods.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | diff --git a/tests/http/test_19_shutdown.py b/tests/http/test_19_shutdown.py index 4ac447d758..388d3955da 100644 --- a/tests/http/test_19_shutdown.py +++ b/tests/http/test_19_shutdown.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | diff --git a/tests/http/test_20_websockets.py b/tests/http/test_20_websockets.py index 5ee8b5e6a9..0d1bdd9ed3 100644 --- a/tests/http/test_20_websockets.py +++ b/tests/http/test_20_websockets.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | @@ -95,7 +93,7 @@ class WsServer: self.wsproc = None return False - self.cerr = open(self.err_file, 'w') + self.cerr = open(self.err_file, 'w') # noqa: SIM115 port_spec = { self.name: socket.SOCK_STREAM } @@ -248,7 +246,7 @@ class TestWebsockets: r = curl.http_download(urls=[url], alpn_proto='http/1.1', with_stats=True, extra_args=xargs) # The CONNECT through the proxy fails as it does not allow it - r.check_exit_code(7) # CURLE_COULDNT_CONNECT + r.check_exit_code(7) # CURLE_COULDNT_CONNECT assert r.stats[0]['http_connect'] == 403, f'{r}' def test_20_11_crazy_pings(self, env: Env): diff --git a/tests/http/test_21_resolve.py b/tests/http/test_21_resolve.py index 940952400a..a287cfdf8f 100644 --- a/tests/http/test_21_resolve.py +++ b/tests/http/test_21_resolve.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | @@ -70,7 +68,7 @@ class TestResolve: run_env = os.environ.copy() run_env['CURL_DBG_RESOLV_FAIL_DELAY'] = f'{delay_ms}' curl = CurlClient(env=env, run_env=run_env, force_resolv=False) - urls = [ f'https://test-{i}.http.curl.invalid/' for i in range(count)] + urls = [f'https://test-{i}.http.curl.invalid/' for i in range(count)] r = curl.http_download(urls=urls, with_stats=True) r.check_exit_code(6) r.check_stats(count=count, http_status=0, exitcode=6) @@ -82,7 +80,7 @@ class TestResolve: run_env = os.environ.copy() run_env['CURL_DBG_RESOLV_FAIL_DELAY'] = f'{delay_ms}' curl = CurlClient(env=env, run_env=run_env, force_resolv=False) - urls = [ f'https://test-{i}.http.curl.invalid/' for i in range(count)] + urls = [f'https://test-{i}.http.curl.invalid/' for i in range(count)] r = curl.http_download(urls=urls, with_stats=True, extra_args=[ '--parallel' ]) @@ -118,7 +116,7 @@ class TestResolve: run_env['CURL_DBG_RESOLV_FAIL_DELAY'] = f'{delay_ms}' run_env['CURL_DBG_RESOLV_MAX_THREADS'] = '1' curl = CurlClient(env=env, run_env=run_env, force_resolv=False) - urls = [ f'https://test-{i}.http.curl.invalid/' for i in range(count)] + urls = [f'https://test-{i}.http.curl.invalid/' for i in range(count)] r = curl.http_download(urls=urls, with_stats=True, extra_args=[ '--parallel', '-6' ]) @@ -301,11 +299,13 @@ class TestResolve: ]) # should fail with CURLE_OPERATION_TIMEOUT or COULDNT_CONNECT assert r.exit_code in (7, 28), f'{r.dump_logs()}' - af_unspec_resolves = [line for line in r.trace_lines if - re.match(r'.* \[DNS] re-queueing query .+ for AF_UNSPEC resolve', line)] + af_unspec_resolves = [ + line for line in r.trace_lines + if re.match(r'.* \[DNS] re-queueing query .+ for AF_UNSPEC resolve', line) + ] assert len(af_unspec_resolves) == 1, f'{r.dump_logs()}' aaaa_resolves = [line for line in r.trace_lines if - re.match(r'.* \* IPv6: fe80::1', line)] + re.match(r'.* \* IPv6: fe80::1', line)] assert len(aaaa_resolves) == 1, f'{r.dump_logs()}' def _clean_files(self, files): diff --git a/tests/http/test_22_httpsrr.py b/tests/http/test_22_httpsrr.py index 0b95472aa7..6ae5d0c728 100644 --- a/tests/http/test_22_httpsrr.py +++ b/tests/http/test_22_httpsrr.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | diff --git a/tests/http/test_30_vsftpd.py b/tests/http/test_30_vsftpd.py index 6627be2613..860c38d5d3 100644 --- a/tests/http/test_30_vsftpd.py +++ b/tests/http/test_30_vsftpd.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | diff --git a/tests/http/test_31_vsftpds.py b/tests/http/test_31_vsftpds.py index 1d8a897fbd..debb8c9b5b 100644 --- a/tests/http/test_31_vsftpds.py +++ b/tests/http/test_31_vsftpds.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | @@ -109,7 +107,7 @@ class TestVsFTPD: ['data-1k', 10, True], ['data-1m', 5, True], ['data-1m', 5, False], - ['data-10m', 2,True] + ['data-10m', 2, True] ]) def test_31_03_download_10_serial(self, env: Env, vsftpds: VsFTPD, docname, count, secure): curl = CurlClient(env=env) @@ -128,7 +126,7 @@ class TestVsFTPD: ['data-1k', 10, True], ['data-1m', 5, True], ['data-1m', 5, False], - ['data-10m', 2,True] + ['data-10m', 2, True] ]) def test_31_04_download_10_parallel(self, env: Env, vsftpds: VsFTPD, docname, count, secure): curl = CurlClient(env=env) diff --git a/tests/http/test_32_ftps_vsftpd.py b/tests/http/test_32_ftps_vsftpd.py index 1e2e965292..6db7fb1eaa 100644 --- a/tests/http/test_32_ftps_vsftpd.py +++ b/tests/http/test_32_ftps_vsftpd.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | @@ -109,7 +107,7 @@ class TestFtpsVsFTPD: ['data-1k', 10, True], ['data-1m', 5, True], ['data-1m', 5, False], - ['data-10m', 2,True] + ['data-10m', 2, True] ]) def test_32_03_download_10_serial(self, env: Env, vsftpds: VsFTPD, docname, count, secure): curl = CurlClient(env=env) @@ -131,7 +129,7 @@ class TestFtpsVsFTPD: docname = 'data-1k' count = 2 url1 = f'ftps://{env.ftp_domain}:{vsftpds.port}/{docname}' - url2 = f'ftp://{env.ftp_domain}:{vsftpds.port}/{docname}' + url2 = f'ftp://{env.ftp_domain}:{vsftpds.port}/{docname}' r = curl.ftp_get(urls=[url1, url2], with_stats=True) r.check_stats(count=count, http_status=226) assert r.total_connects == count + 1, 'should reuse the control conn' diff --git a/tests/http/test_40_socks.py b/tests/http/test_40_socks.py index f4ae322f73..186b75e430 100644 --- a/tests/http/test_40_socks.py +++ b/tests/http/test_40_socks.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | diff --git a/tests/http/test_50_scp.py b/tests/http/test_50_scp.py index 831ee5b3f8..13c36acd65 100644 --- a/tests/http/test_50_scp.py +++ b/tests/http/test_50_scp.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | diff --git a/tests/http/test_51_sftp.py b/tests/http/test_51_sftp.py index acf76ef683..6caaad9d25 100644 --- a/tests/http/test_51_sftp.py +++ b/tests/http/test_51_sftp.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | diff --git a/tests/http/test_60_h3_proxy.py b/tests/http/test_60_h3_proxy.py index 29630e5b07..650644eb0d 100644 --- a/tests/http/test_60_h3_proxy.py +++ b/tests/http/test_60_h3_proxy.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- # *************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | diff --git a/tests/http/testenv/__init__.py b/tests/http/testenv/__init__.py index d2eea486fa..834230a853 100644 --- a/tests/http/testenv/__init__.py +++ b/tests/http/testenv/__init__.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | @@ -23,7 +21,7 @@ # SPDX-License-Identifier: curl # ########################################################################### -# ruff: noqa: F401, E402 +# ruff: noqa: F401 import pytest pytest.register_assert_rewrite("testenv.env", "testenv.curl", "testenv.caddy", diff --git a/tests/http/testenv/caddy.py b/tests/http/testenv/caddy.py index a6c8b58c5c..399bead7a5 100644 --- a/tests/http/testenv/caddy.py +++ b/tests/http/testenv/caddy.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | @@ -113,7 +111,7 @@ class Caddy: args = [ self._caddy, 'run' ] - self._error_fd = open(self._error_log, 'a') + self._error_fd = open(self._error_log, 'a') # noqa: SIM115 self._process = subprocess.Popen(args=args, cwd=self._caddy_dir, stderr=self._error_fd) if self._process.returncode is not None: return False diff --git a/tests/http/testenv/certs.py b/tests/http/testenv/certs.py index 8c25155b24..3102e85399 100644 --- a/tests/http/testenv/certs.py +++ b/tests/http/testenv/certs.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | diff --git a/tests/http/testenv/client.py b/tests/http/testenv/client.py index 0df19e5b42..39fd61054d 100644 --- a/tests/http/testenv/client.py +++ b/tests/http/testenv/client.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | @@ -41,7 +39,7 @@ class LocalClient: def __init__(self, name: str, env: Env, run_dir: Optional[str] = None, timeout: Optional[float] = None, - run_env: Optional[Dict[str,str]] = None): + run_env: Optional[Dict[str, str]] = None): self.name = name self.path = os.path.join(env.build_dir, 'tests/libtest/libtests') self.env = env diff --git a/tests/http/testenv/curl.py b/tests/http/testenv/curl.py index 8e187039ab..f37928471f 100644 --- a/tests/http/testenv/curl.py +++ b/tests/http/testenv/curl.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | @@ -74,7 +72,7 @@ class RunProfile: return self._duration @property - def stats(self) -> Optional[Dict[str,Any]]: + def stats(self) -> Optional[Dict[str, Any]]: return self._stats def sample(self): @@ -134,9 +132,8 @@ class PerfProfile: self._proc.terminate() self._rc = self._proc.returncode with open(self._file, 'w') as cout: - subprocess.run([ - 'sudo', 'perf', 'script' - ], stdout=cout, cwd=self._run_dir, shell=False, check=True) + subprocess.run(['sudo', 'perf', 'script'], + stdout=cout, cwd=self._run_dir, shell=False, check=True) @property def file(self): @@ -496,14 +493,14 @@ class ExecResult: for idx, x in enumerate(self.stats): assert 'remote_port' in x, f'remote_port missing\n{self.dump_stat(x)}' assert x['remote_port'] == remote_port, \ - f'status #{idx} remote_port: expected {remote_port}, '\ - f'got {x["remote_port"]}\n{self.dump_stat(x)}' + f'status #{idx} remote_port: expected {remote_port}, '\ + f'got {x["remote_port"]}\n{self.dump_stat(x)}' if remote_ip is not None: for idx, x in enumerate(self.stats): assert 'remote_ip' in x, f'remote_ip missing\n{self.dump_stat(x)}' assert x['remote_ip'] == remote_ip, \ - f'status #{idx} remote_ip: expected {remote_ip}, '\ - f'got {x["remote_ip"]}\n{self.dump_stat(x)}' + f'status #{idx} remote_ip: expected {remote_ip}, '\ + f'got {x["remote_ip"]}\n{self.dump_stat(x)}' def check_stat_positive(self, s, idx, key): assert key in s, f'stat #{idx} "{key}" missing: {s}' @@ -602,8 +599,8 @@ class ExecResult: return ''.join(lines) def xfer_trace_for(self, xfer_id) -> List[str]: - pat = re.compile(f'^[^[]* \\[{xfer_id}-.*$') - return [line for line in self._stderr if pat.match(line)] + pat = re.compile(f'^[^[]* \\[{xfer_id}-.*$') + return [line for line in self._stderr if pat.match(line)] class CurlClient: @@ -853,11 +850,11 @@ class CurlClient: with_headers=with_headers) def ftp_get(self, urls: List[str], - with_stats: bool = True, - with_profile: bool = False, - with_tcpdump: bool = False, - no_save: bool = False, - extra_args: Optional[List[str]] = None): + with_stats: bool = True, + with_profile: bool = False, + with_tcpdump: bool = False, + no_save: bool = False, + extra_args: Optional[List[str]] = None): if extra_args is None: extra_args = [] if no_save: @@ -882,11 +879,11 @@ class CurlClient: with_tcpdump=with_tcpdump) def ftp_ssl_get(self, urls: List[str], - with_stats: bool = True, - with_profile: bool = False, - with_tcpdump: bool = False, - no_save: bool = False, - extra_args: Optional[List[str]] = None): + with_stats: bool = True, + with_profile: bool = False, + with_tcpdump: bool = False, + no_save: bool = False, + extra_args: Optional[List[str]] = None): if extra_args is None: extra_args = [] extra_args.extend([ @@ -1164,7 +1161,7 @@ class CurlClient: elif insecure: args.append('--insecure') elif active_options and ("--cacert" in active_options or - "--capath" in active_options): + "--capath" in active_options): pass elif u.hostname: args.extend(["--cacert", self.env.ca.cert_file]) @@ -1246,9 +1243,8 @@ class CurlClient: stacks_collapsed = f'{perf.file}.collapsed' log.info(f'collapsing stacks into {stacks_collapsed}') with open(stacks_collapsed, 'w') as cout, open(file_err, 'w') as cerr: - subprocess.run([ - fg_collapse, perf.file - ], stdout=cout, stderr=cerr, cwd=self._run_dir, shell=False, check=True) + subprocess.run([fg_collapse, perf.file], + stdout=cout, stderr=cerr, cwd=self._run_dir, shell=False, check=True) return stacks_collapsed def _dtrace_collapse(self, dtrace: DTraceProfile, file_err): @@ -1260,9 +1256,8 @@ class CurlClient: stacks_collapsed = f'{dtrace.file}.collapsed' log.info(f'collapsing stacks into {stacks_collapsed}') with open(stacks_collapsed, 'w') as cout, open(file_err, 'a') as cerr: - subprocess.run([ - fg_collapse, dtrace.file - ], stdout=cout, stderr=cerr, cwd=self._run_dir, shell=False, check=True) + subprocess.run([fg_collapse, dtrace.file], + stdout=cout, stderr=cerr, cwd=self._run_dir, shell=False, check=True) return stacks_collapsed def _generate_flame(self, curl_args: List[str], @@ -1293,11 +1288,9 @@ class CurlClient: title = cmdline subtitle = '' with open(file_svg, 'w') as cout, open(file_err, 'a') as cerr: - subprocess.run([ - fg_gen_flame, '--colors', 'green', - '--title', title, '--subtitle', subtitle, - stacks_collapsed - ], stdout=cout, stderr=cerr, cwd=self._run_dir, shell=False, check=True) + subprocess.run([fg_gen_flame, '--colors', 'green', '--title', title, '--subtitle', + subtitle, stacks_collapsed], + stdout=cout, stderr=cerr, cwd=self._run_dir, shell=False, check=True) def mk_altsvc_file(self, name, src_alpn, src_host, src_port, dest_alpn, dest_host, dest_port): diff --git a/tests/http/testenv/dante.py b/tests/http/testenv/dante.py index b2ea4dd0cf..43b058e196 100644 --- a/tests/http/testenv/dante.py +++ b/tests/http/testenv/dante.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | @@ -128,7 +126,7 @@ class Dante: '-p', f'{self._pid_file}', '-d', '0', ] - self._error_fd = open(self._error_log, 'a') + self._error_fd = open(self._error_log, 'a') # noqa: SIM115 self._process = subprocess.Popen(args=args, stderr=self._error_fd) if self._process.returncode is not None: return False @@ -137,8 +135,8 @@ class Dante: def wait_live(self, timeout: timedelta): curl = CurlClient(env=self.env, run_dir=self._tmp_dir, timeout=timeout.total_seconds(), socks_args=[ - '--socks5', f'127.0.0.1:{self._port}' - ]) + '--socks5', f'127.0.0.1:{self._port}' + ]) try_until = datetime.now() + timeout while datetime.now() < try_until: r = curl.http_get(url=f'http://{self.env.domain1}:{self.env.http_port}/') diff --git a/tests/http/testenv/dnsd.py b/tests/http/testenv/dnsd.py index 8f6bb3edc8..18cfafcc38 100644 --- a/tests/http/testenv/dnsd.py +++ b/tests/http/testenv/dnsd.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | @@ -128,7 +126,7 @@ class Dnsd: '--logfile', f'{self._log_file}', '--pidfile', f'{self._pid_file}', ] - self._error_fd = open(self._error_log, 'a') + self._error_fd = open(self._error_log, 'a') # noqa: SIM115 self._process = subprocess.Popen(args=args, stderr=self._error_fd) if self._process.returncode is not None: return False diff --git a/tests/http/testenv/env.py b/tests/http/testenv/env.py index 5acb3ab67a..24c2276c1e 100644 --- a/tests/http/testenv/env.py +++ b/tests/http/testenv/env.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- # *************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | @@ -513,8 +511,8 @@ class Env: def curl_version_at_least(min_version) -> bool: version = Env.curl_version() return Env.CONFIG.versiontuple(min_version) <= Env.CONFIG.versiontuple( - version - ) + version + ) @staticmethod def curl_features_string() -> str: @@ -537,7 +535,7 @@ class Env: prefix = f"{libname.lower()}/" for lversion in Env.CONFIG.curl_props["lib_versions"]: if lversion.startswith(prefix): - return lversion[len(prefix) :] + return lversion[len(prefix):] return "unknown" @staticmethod @@ -914,14 +912,14 @@ class Env: fpath = os.path.join(indir, fname) s10 = "0123456789" s = round((line_length / 10) + 1) * s10 - s = s[0 : line_length - 11] + s = s[0:line_length - 11] with open(fpath, "w") as fd: for i in range(int(fsize / line_length)): fd.write(f"{i:09d}-{s}\n") remain = int(fsize % line_length) if remain != 0: i = int(fsize / line_length) + 1 - fd.write(f"{i:09d}-{s}"[0 : remain - 1] + "\n") + fd.write(f"{i:09d}-{s}"[0:remain - 1] + "\n") return fpath def make_data_gzipbomb(self, indir: str, fname: str, fsize: int) -> str: diff --git a/tests/http/testenv/h2o.py b/tests/http/testenv/h2o.py index deb3608d3a..e6241c2b4b 100644 --- a/tests/http/testenv/h2o.py +++ b/tests/http/testenv/h2o.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- # *************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | @@ -133,7 +131,7 @@ class H2o: self._loaded_cred_name = self._cred_name self.write_config() args = [self._cmd, "-c", self._conf_file] - self._error_fd = open(self._stderr, "a") + self._error_fd = open(self._stderr, "a") # noqa: SIM115 self._process = subprocess.Popen(args=args, stderr=self._error_fd) if self._process.returncode is not None: return False diff --git a/tests/http/testenv/httpd.py b/tests/http/testenv/httpd.py index 10ccce0c4a..c2a0a22b8f 100644 --- a/tests/http/testenv/httpd.py +++ b/tests/http/testenv/httpd.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | @@ -583,9 +581,8 @@ class Httpd: if not os.path.exists(out_source) or \ os.stat(in_source).st_mtime > os.stat(out_source).st_mtime: shutil.copy(in_source, out_source) - p = subprocess.run([ - self.env.apxs, '-c', out_source - ], capture_output=True, cwd=out_dir, check=False) + p = subprocess.run([self.env.apxs, '-c', out_source], + capture_output=True, cwd=out_dir, check=False) rv = p.returncode if rv != 0: log.error(f"compiling mod_curltest failed: {p.stderr}") diff --git a/tests/http/testenv/nghttpx.py b/tests/http/testenv/nghttpx.py index 37c72ad945..3caa99dcca 100644 --- a/tests/http/testenv/nghttpx.py +++ b/tests/http/testenv/nghttpx.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | @@ -270,7 +268,7 @@ class NghttpxQuic(Nghttpx): '--frontend-http3-max-connection-window-size=100M', # f'--frontend-quic-debug-log', ]) - self._error_fd = open(self._stderr, 'a') + self._error_fd = open(self._stderr, 'a') # noqa: SIM115 self._process = subprocess.Popen(args=args, stderr=self._error_fd) if self._process.returncode is not None: return False @@ -320,7 +318,7 @@ class NghttpxFwd(Nghttpx): creds.pkey_file, creds.cert_file, ] - self._error_fd = open(self._stderr, 'a') + self._error_fd = open(self._stderr, 'a') # noqa: SIM115 self._process = subprocess.Popen(args=args, stderr=self._error_fd) if self._process.returncode is not None: return False diff --git a/tests/http/testenv/ports.py b/tests/http/testenv/ports.py index 10accb2f3b..2436d40767 100644 --- a/tests/http/testenv/ports.py +++ b/tests/http/testenv/ports.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | diff --git a/tests/http/testenv/sshd.py b/tests/http/testenv/sshd.py index 49c39ce494..57c7d1e34a 100644 --- a/tests/http/testenv/sshd.py +++ b/tests/http/testenv/sshd.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | @@ -235,7 +233,7 @@ class Sshd: run_env = os.environ.copy() # does not have any effect, sadly # run_env['HOME'] = f'{self._home_dir}' - self._error_fd = open(self._sshd_log, 'a') + self._error_fd = open(self._sshd_log, 'a') # noqa: SIM115 self._process = subprocess.Popen(args=args, stderr=self._error_fd, env=run_env) if self._process.returncode is not None: return False diff --git a/tests/http/testenv/vsftpd.py b/tests/http/testenv/vsftpd.py index e2c33edee3..7cd9596b16 100644 --- a/tests/http/testenv/vsftpd.py +++ b/tests/http/testenv/vsftpd.py @@ -1,5 +1,3 @@ -#!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | @@ -146,7 +144,7 @@ class VsFTPD: self._cmd, f'{self._conf_file}', ] - self._error_fd = open(self._error_log, 'a') + self._error_fd = open(self._error_log, 'a') # noqa: SIM115 self._process = subprocess.Popen(args=args, stderr=self._error_fd) if self._process.returncode is not None: return False diff --git a/tests/http/testenv/ws_4frames_server.py b/tests/http/testenv/ws_4frames_server.py index 8d5655aa5c..42d6e9dc29 100755 --- a/tests/http/testenv/ws_4frames_server.py +++ b/tests/http/testenv/ws_4frames_server.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | diff --git a/tests/http/testenv/ws_echo_server.py b/tests/http/testenv/ws_echo_server.py index fddd26f271..a063b03079 100755 --- a/tests/http/testenv/ws_echo_server.py +++ b/tests/http/testenv/ws_echo_server.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | diff --git a/tests/negtelnetserver.py b/tests/negtelnetserver.py index a65b156630..4e65b62ec4 100755 --- a/tests/negtelnetserver.py +++ b/tests/negtelnetserver.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- # # Project ___| | | | _ \| | # / __| | | | |_) | | diff --git a/tests/smbserver.py b/tests/smbserver.py index 44daefc15a..6623aac708 100755 --- a/tests/smbserver.py +++ b/tests/smbserver.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- # # Project ___| | | | _ \| | # / __| | | | |_) | | @@ -153,8 +152,9 @@ def smbserver(options): class TestSmbServer(imp_smbserver.SMBSERVER): """ - Test server for SMB which subclasses the impacket SMBSERVER and provides - test functionality. + Test server for SMB. + + It subclasses the impacket SMBSERVER and provides test functionality. """ def __init__(self, @@ -176,9 +176,10 @@ class TestSmbServer(imp_smbserver.SMBSERVER): def create_and_x(self, conn_id, smb_server, smb_command, recv_packet): """ - Our version of smbComNtCreateAndX looks for special test files and - fools the rest of the framework into opening them as if they were - normal files. + Our version of smbComNtCreateAndX. + + It looks for special test files and fools the rest of the framework + into opening them as if they were normal files. """ conn_data = smb_server.getConnectionData(conn_id) @@ -372,9 +373,9 @@ def get_options(): parser = argparse.ArgumentParser() parser.add_argument("--port", action="store", default=9017, - type=int, help="port to listen on") + type=int, help="port to listen on") parser.add_argument("--host", action="store", default="127.0.0.1", - help="host to listen on") + help="host to listen on") parser.add_argument("--verbose", action="store", type=int, default=0, help="verbose output") parser.add_argument("--pidfile", action="store", diff --git a/tests/util.py b/tests/util.py index 2921e93aa8..ef212da073 100755 --- a/tests/util.py +++ b/tests/util.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- # # Project ___| | | | _ \| | # / __| | | | |_) | | From 3901c16933c2ab327bf9030e0d49f1161d603fbb Mon Sep 17 00:00:00 2001 From: Dan Fandrich Date: Sat, 25 Jul 2026 13:49:29 -0700 Subject: [PATCH 09/15] tests: simplify by removing unneeded Python code * combine separate if statements * remove an unneeded encode() call * remove unneeded returns * simplify code when returning early This fixes ruff rules SIM102, SIM114, UP012, PLR1711. --- tests/http/scorecard.py | 2 +- tests/http/test_02_download.py | 4 ---- tests/http/test_11_unix.py | 4 ++-- tests/http/test_17_ssl_use.py | 24 +++++++++++------------- tests/http/testenv/certs.py | 26 ++++++++++++-------------- tests/http/testenv/h2o.py | 2 -- tests/smbserver.py | 14 ++++++-------- tests/util.py | 18 +++++++++--------- 8 files changed, 41 insertions(+), 53 deletions(-) diff --git a/tests/http/scorecard.py b/tests/http/scorecard.py index 1550ccb99e..41682ae132 100755 --- a/tests/http/scorecard.py +++ b/tests/http/scorecard.py @@ -795,7 +795,7 @@ def run_score(args, protocol): socks_args = None if args.socks4 and args.socks5: raise ScoreCardError('unable to run --socks4 and --socks5 together') - elif args.socks4 or args.socks5: + if args.socks4 or args.socks5: sockd = Dante(env=env) if sockd: assert sockd.initial_start() diff --git a/tests/http/test_02_download.py b/tests/http/test_02_download.py index 437db80ae4..940245920d 100644 --- a/tests/http/test_02_download.py +++ b/tests/http/test_02_download.py @@ -701,10 +701,6 @@ class TestDownload: if url_junk <= 1024: r.check_exit_code(0) r.check_response(http_status=200) - elif url_junk <= 16 * 1024: - r.check_exit_code(0) - # server replies with 414, Request URL too long - r.check_response(http_status=414) elif url_junk <= 32 * 1024: r.check_exit_code(0) # server replies with 414, Request URL too long diff --git a/tests/http/test_11_unix.py b/tests/http/test_11_unix.py index 6ba500e1ce..115c74f297 100644 --- a/tests/http/test_11_unix.py +++ b/tests/http/test_11_unix.py @@ -71,12 +71,12 @@ class UDSFaker: c, client_address = self._socket.accept() try: c.recv(16) - c.sendall("""HTTP/1.1 200 Ok + c.sendall(b"""HTTP/1.1 200 Ok Server: UdsFaker Content-Type: application/json Content-Length: 19 -{ "host": "faked" }""".encode()) +{ "host": "faked" }""") finally: c.close() diff --git a/tests/http/test_17_ssl_use.py b/tests/http/test_17_ssl_use.py index c5b5e144f3..54f72cf27e 100644 --- a/tests/http/test_17_ssl_use.py +++ b/tests/http/test_17_ssl_use.py @@ -80,9 +80,8 @@ class TestSSLUse: count = 3 exp_resumed = 'Resumed' xargs = ['--sessionid', '--tls-max', tls_max, f'--tlsv{tls_max}'] - if env.curl_uses_lib('libressl'): - if tls_max == '1.3': - exp_resumed = 'Initial' # 1.2 works in LibreSSL, but 1.3 does not, TODO + if env.curl_uses_lib('libressl') and tls_max == '1.3': + exp_resumed = 'Initial' # 1.2 works in LibreSSL, but 1.3 does not, TODO if env.curl_uses_lib('rustls-ffi'): exp_resumed = 'Initial' # Rustls does not support sessions, TODO if env.curl_uses_lib('mbedtls') and tls_max == '1.3' and \ @@ -265,9 +264,9 @@ class TestSSLUse: elif env.curl_uses_lib('schannel'): # not in CI, so untested if ciphers12 is not None: pytest.skip('Schannel does not support setting TLSv1.2 ciphers by name') - elif env.curl_uses_lib('mbedtls') and not env.curl_lib_version_at_least('mbedtls', '3.6.0'): - if tls_proto == 'TLSv1.3': - pytest.skip('mbedTLS < 3.6.0 does not support TLSv1.3') + elif (env.curl_uses_lib('mbedtls') and not env.curl_lib_version_at_least('mbedtls', '3.6.0') + and tls_proto == 'TLSv1.3'): + pytest.skip('mbedTLS < 3.6.0 does not support TLSv1.3') # test extra_args = ['--tls13-ciphers', ':'.join(ciphers13)] if ciphers13 else [] extra_args += ['--ciphers', ':'.join(ciphers12)] if ciphers12 else [] @@ -317,13 +316,12 @@ class TestSSLUse: ]) httpd.reload_if_config_changed() # curl's TLS backend supported version - if env.curl_uses_lib('gnutls') or \ - env.curl_uses_lib('quiche') or \ - env.curl_uses_lib('aws-lc') or \ - env.curl_uses_lib('boringssl'): - curl_supported = [0x301, 0x302, 0x303, 0x304] - elif env.curl_uses_lib('openssl') and \ - env.curl_lib_version_before('openssl', '3.0.0'): + if (env.curl_uses_lib('gnutls') or + env.curl_uses_lib('quiche') or + env.curl_uses_lib('aws-lc') or + env.curl_uses_lib('boringssl') or + (env.curl_uses_lib('openssl') and + env.curl_lib_version_before('openssl', '3.0.0'))): curl_supported = [0x301, 0x302, 0x303, 0x304] else: # most SSL backends dropped support for TLSv1.0, TLSv1.1 curl_supported = [0x303, 0x304] diff --git a/tests/http/testenv/certs.py b/tests/http/testenv/certs.py index 3102e85399..81eb09059d 100644 --- a/tests/http/testenv/certs.py +++ b/tests/http/testenv/certs.py @@ -389,20 +389,18 @@ class TestCA: :returns: the certificate and private key PEM file paths """ if spec.domains and len(spec.domains): - creds = TestCA._make_server_credentials(name=spec.name, domains=spec.domains, - issuer=issuer, valid_from=valid_from, - valid_to=valid_to, key_type=key_type) - elif spec.client: - creds = TestCA._make_client_credentials(name=spec.name, issuer=issuer, - email=spec.email, valid_from=valid_from, - valid_to=valid_to, key_type=key_type) - elif spec.name: - creds = TestCA._make_ca_credentials(name=spec.name, issuer=issuer, - valid_from=valid_from, valid_to=valid_to, - key_type=key_type) - else: - raise CertError(f"unrecognized certificate specification: {spec}") - return creds + return TestCA._make_server_credentials(name=spec.name, domains=spec.domains, + issuer=issuer, valid_from=valid_from, + valid_to=valid_to, key_type=key_type) + if spec.client: + return TestCA._make_client_credentials(name=spec.name, issuer=issuer, + email=spec.email, valid_from=valid_from, + valid_to=valid_to, key_type=key_type) + if spec.name: + return TestCA._make_ca_credentials(name=spec.name, issuer=issuer, + valid_from=valid_from, valid_to=valid_to, + key_type=key_type) + raise CertError(f"unrecognized certificate specification: {spec}") @staticmethod def _make_x509_name(org_name: Optional[str] = None, common_name: Optional[str] = None, parent: x509.Name = None) -> x509.Name: diff --git a/tests/http/testenv/h2o.py b/tests/http/testenv/h2o.py index e6241c2b4b..f36e6975ce 100644 --- a/tests/http/testenv/h2o.py +++ b/tests/http/testenv/h2o.py @@ -95,7 +95,6 @@ class H2o: def _rmf(self, path): if os.path.isfile(path): os.remove(path) - return def _dump_file(self, path, lines): if os.path.isfile(path): @@ -106,7 +105,6 @@ class H2o: def _mkpath(self, path): if not os.path.exists(path): os.makedirs(path) - return def _log(self, level, msg): getattr(log, level)(f"[{self._name}] {msg}") diff --git a/tests/smbserver.py b/tests/smbserver.py index 6623aac708..67ca6b2962 100755 --- a/tests/smbserver.py +++ b/tests/smbserver.py @@ -293,15 +293,13 @@ class TestSmbServer(imp_smbserver.SMBSERVER): # If we have a rootFid, the path is relative to that fid path = conn_data["OpenedFiles"][root_fid]["FileName"] log.debug(f'RootFid present {path}!') - else: - if "path" in conn_shares[tid]: - path = conn_shares[tid]["path"] - else: - raise SmbError(STATUS_ACCESS_DENIED, "Connection share had no path") - else: - raise SmbError(imp_smbserver.STATUS_SMB_BAD_TID, "TID was invalid") + return path - return path + if "path" in conn_shares[tid]: + return conn_shares[tid]["path"] + + raise SmbError(STATUS_ACCESS_DENIED, "Connection share had no path") + raise SmbError(imp_smbserver.STATUS_SMB_BAD_TID, "TID was invalid") def get_server_path(self, requested_filename): log.debug("[SMB] Get server path '%s'", requested_filename) diff --git a/tests/util.py b/tests/util.py index ef212da073..bc94f41f7e 100755 --- a/tests/util.py +++ b/tests/util.py @@ -48,15 +48,15 @@ class ClosingFileHandler(logging.StreamHandler): if callable(setStream): return setStream(stream) if stream is self.stream: - result = None - else: - result = self.stream - self.acquire() - try: - self.flush() - self.stream = stream - finally: - self.release() + return None + + result = self.stream + self.acquire() + try: + self.flush() + self.stream = stream + finally: + self.release() return result From b151a0bb901b8740c0025483c7fe375e65466dae Mon Sep 17 00:00:00 2001 From: Dan Fandrich Date: Sat, 25 Jul 2026 14:05:01 -0700 Subject: [PATCH 10/15] tests: use simpler constructions in Python code * call super() without arguments * mark an unused variable as such * simplify by using dict getter for default values * use writelines() when possible * use dedent to simplify some text formatting * avoid items() on dict in a loop when unnecessary * replace most Python format() calls with f-strings * use capture_output in subprocess.run This fixes ruff rules FLY002, FURB122, PERF102, RUF059, SIM401, UP008, UP022, UP030. --- tests/dictserver.py | 2 +- tests/http/test_11_unix.py | 2 +- tests/http/testenv/caddy.py | 2 +- tests/http/testenv/certs.py | 15 ++++++--------- tests/http/testenv/client.py | 2 +- tests/http/testenv/curl.py | 2 +- tests/http/testenv/env.py | 3 +-- tests/http/testenv/httpd.py | 21 ++++++++++----------- tests/http/testenv/nghttpx.py | 9 +++++---- tests/negtelnetserver.py | 4 +--- tests/smbserver.py | 4 ++-- tests/util.py | 9 ++++----- 12 files changed, 34 insertions(+), 41 deletions(-) diff --git a/tests/dictserver.py b/tests/dictserver.py index ea9f586c44..87a00d61d0 100755 --- a/tests/dictserver.py +++ b/tests/dictserver.py @@ -96,7 +96,7 @@ class DictHandler(socketserver.BaseRequestHandler): response_data = "No matches" # Send back a failure to find. - response = "552 {0}\n".format(response_data) + response = f"552 {response_data}\n" log.debug("[DICT] Responding with %r", response) self.request.sendall(response.encode("utf-8")) diff --git a/tests/http/test_11_unix.py b/tests/http/test_11_unix.py index 115c74f297..9321d71414 100644 --- a/tests/http/test_11_unix.py +++ b/tests/http/test_11_unix.py @@ -68,7 +68,7 @@ class UDSFaker: def _process(self): while self._done is False: try: - c, client_address = self._socket.accept() + c, _client_address = self._socket.accept() try: c.recv(16) c.sendall(b"""HTTP/1.1 200 Ok diff --git a/tests/http/testenv/caddy.py b/tests/http/testenv/caddy.py index 399bead7a5..6d79559b7e 100644 --- a/tests/http/testenv/caddy.py +++ b/tests/http/testenv/caddy.py @@ -47,7 +47,7 @@ class Caddy: def __init__(self, env: Env): self.env = env - self._caddy = os.environ['CADDY'] if 'CADDY' in os.environ else env.caddy + self._caddy = os.environ.get('CADDY', env.caddy) self._caddy_dir = os.path.join(env.gen_dir, 'caddy') self._docs_dir = os.path.join(self._caddy_dir, 'docs') self._conf_file = os.path.join(self._caddy_dir, 'Caddyfile') diff --git a/tests/http/testenv/certs.py b/tests/http/testenv/certs.py index 81eb09059d..6376a3d445 100644 --- a/tests/http/testenv/certs.py +++ b/tests/http/testenv/certs.py @@ -280,8 +280,7 @@ class CertStore: with open(cert_file, "wb") as fd: fd.write(creds.cert_pem) if chain: - for c in chain: - fd.write(c.cert_pem) + fd.writelines(c.cert_pem for c in chain) if pkey_file is None: fd.write(creds.pkey_pem) if pkey_file is not None: @@ -290,8 +289,7 @@ class CertStore: with open(comb_file, "wb") as fd: fd.write(creds.cert_pem) if chain: - for c in chain: - fd.write(c.cert_pem) + fd.writelines(c.cert_pem for c in chain) fd.write(creds.pkey_pem) creds.set_files(cert_file, pkey_file, comb_file) self._add_credentials(name, creds) @@ -306,8 +304,7 @@ class CertStore: chain = chain[:-1] chain_file = os.path.join(self._store_dir, f'{name}-{infix}.pem') with open(chain_file, "wb") as fd: - for c in chain: - fd.write(c.cert_pem) + fd.writelines(c.cert_pem for c in chain) def _add_credentials(self, name: str, creds: Credentials): if name not in self._creds_by_name: @@ -315,14 +312,14 @@ class CertStore: self._creds_by_name[name].append(creds) def get_credentials_for_name(self, name) -> List[Credentials]: - return self._creds_by_name[name] if name in self._creds_by_name else [] + return self._creds_by_name.get(name, []) def get_cert_file(self, name: str, key_type=None) -> str: - key_infix = ".{0}".format(key_type) if key_type is not None else "" + key_infix = f".{key_type}" if key_type is not None else "" return os.path.join(self._store_dir, f'{name}{key_infix}.cert.pem') def get_pkey_file(self, name: str, key_type=None) -> str: - key_infix = ".{0}".format(key_type) if key_type is not None else "" + key_infix = f".{key_type}" if key_type is not None else "" return os.path.join(self._store_dir, f'{name}{key_infix}.pkey.pem') def get_combined_file(self, name: str, key_type=None) -> str: diff --git a/tests/http/testenv/client.py b/tests/http/testenv/client.py index 39fd61054d..a2e72237f4 100644 --- a/tests/http/testenv/client.py +++ b/tests/http/testenv/client.py @@ -45,7 +45,7 @@ class LocalClient: self.env = env self._run_env = run_env self._timeout = timeout if timeout else env.test_timeout - self._curl = os.environ['CURL'] if 'CURL' in os.environ else env.curl + self._curl = os.environ.get('CURL', env.curl) self._run_dir = run_dir if run_dir else os.path.join(env.gen_dir, name) self._stdoutfile = f'{self._run_dir}/stdout' self._stderrfile = f'{self._run_dir}/stderr' diff --git a/tests/http/testenv/curl.py b/tests/http/testenv/curl.py index f37928471f..7b026e325f 100644 --- a/tests/http/testenv/curl.py +++ b/tests/http/testenv/curl.py @@ -627,7 +627,7 @@ class CurlClient: socks_args: Optional[List[str]] = None): self.env = env self._timeout = timeout if timeout else env.test_timeout - self._curl = os.environ['CURL'] if 'CURL' in os.environ else env.curl + self._curl = os.environ.get('CURL', env.curl) self._run_dir = run_dir if run_dir else os.path.join(env.gen_dir, 'curl') self._stdoutfile = f'{self._run_dir}/curl.stdout' self._stderrfile = f'{self._run_dir}/curl.stderr' diff --git a/tests/http/testenv/env.py b/tests/http/testenv/env.py index 24c2276c1e..0c19d6bd16 100644 --- a/tests/http/testenv/env.py +++ b/tests/http/testenv/env.py @@ -914,8 +914,7 @@ class Env: s = round((line_length / 10) + 1) * s10 s = s[0:line_length - 11] with open(fpath, "w") as fd: - for i in range(int(fsize / line_length)): - fd.write(f"{i:09d}-{s}\n") + fd.writelines(f"{i:09d}-{s}\n" for i in range(int(fsize / line_length))) remain = int(fsize % line_length) if remain != 0: i = int(fsize / line_length) + 1 diff --git a/tests/http/testenv/httpd.py b/tests/http/testenv/httpd.py index c2a0a22b8f..c389a9a56c 100644 --- a/tests/http/testenv/httpd.py +++ b/tests/http/testenv/httpd.py @@ -29,6 +29,7 @@ import os import shutil import socket import subprocess +import textwrap import time from datetime import datetime, timedelta from json import JSONEncoder @@ -137,8 +138,7 @@ class Httpd: env['APACHE_RUN_USER'] = os.environ['USER'] env['APACHE_LOCK_DIR'] = self._lock_dir env['APACHE_CONFDIR'] = self._apache_dir - p = subprocess.run(args, stderr=subprocess.PIPE, stdout=subprocess.PIPE, - cwd=self.env.gen_dir, + p = subprocess.run(args, capture_output=True, cwd=self.env.gen_dir, input=intext.encode() if intext else None, env=env, check=True) start = datetime.now() @@ -170,7 +170,7 @@ class Httpd: def start(self): # assure ports are allocated - for key, _ in Httpd.PORT_SPECS.items(): + for key in Httpd.PORT_SPECS: assert self.ports[key] is not None if self._maybe_running: self.stop() @@ -479,14 +479,13 @@ class Httpd: fd.write("\n".join(conf)) with open(os.path.join(self._conf_dir, 'mime.types'), 'w') as fd: - fd.write("\n".join([ - 'text/plain txt', - 'text/html html', - 'application/json json', - 'application/x-gzip gzip', - 'application/x-gzip gz', - '' - ])) + fd.write(textwrap.dedent("""\ + text/plain txt + text/html html + application/json json + application/x-gzip gzip + application/x-gzip gz + """)) def _get_proxy_conf(self): if self._proxy_auth_basic: diff --git a/tests/http/testenv/nghttpx.py b/tests/http/testenv/nghttpx.py index 3caa99dcca..50dd5e2152 100644 --- a/tests/http/testenv/nghttpx.py +++ b/tests/http/testenv/nghttpx.py @@ -27,6 +27,7 @@ import os import signal import socket import subprocess +import textwrap import time from datetime import datetime, timedelta from typing import Dict, Optional @@ -203,10 +204,10 @@ class Nghttpx: def _write_config(self): with open(self._conf_file, 'w') as fd: - fd.write('# nghttpx test config') - fd.write("\n".join([ - '# do we need something here?' - ])) + fd.write(textwrap.dedent("""\ + # nghttpx test config + # do we need something here? + """)) class NghttpxQuic(Nghttpx): diff --git a/tests/negtelnetserver.py b/tests/negtelnetserver.py index 4e65b62ec4..ad7cb53e98 100755 --- a/tests/negtelnetserver.py +++ b/tests/negtelnetserver.py @@ -310,9 +310,7 @@ def setup_logging(options): root_logger = logging.getLogger() add_stdout = False - formatter = logging.Formatter("%(asctime)s %(levelname)-5.5s " - "[{ident}] %(message)s" - .format(ident=IDENT)) + formatter = logging.Formatter(f"%(asctime)s %(levelname)-5.5s [{IDENT}] %(message)s") # Write out to a logfile if options.logfile: diff --git a/tests/smbserver.py b/tests/smbserver.py index 67ca6b2962..1072fd239d 100755 --- a/tests/smbserver.py +++ b/tests/smbserver.py @@ -64,7 +64,7 @@ class ShutdownHandler(threading.Thread): """ def __init__(self, server): - super(ShutdownHandler, self).__init__() + super().__init__() self.server = server self.shutdown_event = threading.Event() @@ -351,7 +351,7 @@ class TestSmbServer(imp_smbserver.SMBSERVER): class SmbError(Exception): def __init__(self, error_code, error_message): - super(SmbError, self).__init__(error_message) + super().__init__(error_message) self.error_code = error_code diff --git a/tests/util.py b/tests/util.py index bc94f41f7e..7c0ad4b499 100755 --- a/tests/util.py +++ b/tests/util.py @@ -33,18 +33,18 @@ REPLY_DATA = re.compile("[ \t\n\r]*(.*?)", re.MULTILINE class ClosingFileHandler(logging.StreamHandler): def __init__(self, filename): - super(ClosingFileHandler, self).__init__() + super().__init__() self.filename = os.path.abspath(filename) self.setStream(None) def emit(self, record): with open(self.filename, "a") as fp: self.setStream(fp) - super(ClosingFileHandler, self).emit(record) + super().emit(record) self.setStream(None) def setStream(self, stream): - setStream = getattr(super(ClosingFileHandler, self), 'setStream', None) + setStream = getattr(super(), 'setStream', None) if callable(setStream): return setStream(stream) if stream is self.stream: @@ -66,8 +66,7 @@ class TestData: def get_test_data(self, test_number): # Create the test filename - filename = os.path.join(self.data_folder, - "test{0}".format(test_number)) + filename = os.path.join(self.data_folder, f"test{test_number}") log.debug("Parsing file %s", filename) From e13362c20accd210de60035825f7195f9679570b Mon Sep 17 00:00:00 2001 From: Dan Fandrich Date: Sat, 25 Jul 2026 13:23:21 -0700 Subject: [PATCH 11/15] tests: address mutable class vars and naive datetime in Python code Mark Python mutable class variables with ClassVar, to denote that the danger this can cause has been considered. Since any change made to these in any object affects all other objects, this can cause locality errors. However, as used in the test suite, they are are never modified and so they are annotated as being intended. Always set a timezone in datetime objects, as mixing naive and timezone-aware object can cause errors. These fix ruff rules DTZ005, RUF012. --- tests/http/test_17_ssl_use.py | 11 +++++++---- tests/http/test_20_websockets.py | 6 +++--- tests/http/testenv/caddy.py | 14 +++++++------- tests/http/testenv/certs.py | 6 +++--- tests/http/testenv/client.py | 6 +++--- tests/http/testenv/curl.py | 18 +++++++++--------- tests/http/testenv/dante.py | 6 +++--- tests/http/testenv/dnsd.py | 6 +++--- tests/http/testenv/h2o.py | 20 ++++++++++---------- tests/http/testenv/httpd.py | 22 +++++++++++----------- tests/http/testenv/nghttpx.py | 28 ++++++++++++++-------------- tests/http/testenv/sshd.py | 6 +++--- tests/http/testenv/vsftpd.py | 10 +++++----- 13 files changed, 81 insertions(+), 78 deletions(-) diff --git a/tests/http/test_17_ssl_use.py b/tests/http/test_17_ssl_use.py index 54f72cf27e..5d59765b69 100644 --- a/tests/http/test_17_ssl_use.py +++ b/tests/http/test_17_ssl_use.py @@ -26,6 +26,8 @@ import json import logging import os import re +from dataclasses import dataclass +from typing import ClassVar, Dict, List import pytest from testenv import CurlClient, Env, LocalClient @@ -33,15 +35,16 @@ from testenv import CurlClient, Env, LocalClient log = logging.getLogger(__name__) +@dataclass(frozen=True) class TLSDefs: - TLS_VERSIONS = ['TLSv1', 'TLSv1.1', 'TLSv1.2', 'TLSv1.3'] - TLS_VERSION_IDS = { + TLS_VERSIONS: ClassVar[List[str]] = ['TLSv1', 'TLSv1.1', 'TLSv1.2', 'TLSv1.3'] + TLS_VERSION_IDS: ClassVar[Dict[str, int]] = { 'TLSv1': 0x301, 'TLSv1.1': 0x302, 'TLSv1.2': 0x303, 'TLSv1.3': 0x304 } - CURL_ARG_MIN_VERSION_ID = { + CURL_ARG_MIN_VERSION_ID: ClassVar[Dict[str, int]] = { 'none': 0x0, 'tlsv1': 0x301, 'tlsv1.0': 0x301, @@ -49,7 +52,7 @@ class TLSDefs: 'tlsv1.2': 0x303, 'tlsv1.3': 0x304, } - CURL_ARG_MAX_VERSION_ID = { + CURL_ARG_MAX_VERSION_ID: ClassVar[Dict[str, int]] = { 'none': 0x0, '1.0': 0x301, '1.1': 0x302, diff --git a/tests/http/test_20_websockets.py b/tests/http/test_20_websockets.py index 0d1bdd9ed3..b559383c93 100644 --- a/tests/http/test_20_websockets.py +++ b/tests/http/test_20_websockets.py @@ -32,7 +32,7 @@ import socket import subprocess import threading import time -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone from typing import Dict import pytest @@ -59,8 +59,8 @@ class WsServer: def check_alive(self, env, port, timeout=Env.SERVER_TIMEOUT): curl = CurlClient(env=env) url = f'http://localhost:{port}/' - end = datetime.now() + timedelta(seconds=timeout) - while datetime.now() < end: + end = datetime.now(timezone.utc) + timedelta(seconds=timeout) + while datetime.now(timezone.utc) < end: r = curl.http_download(urls=[url]) if r.exit_code == 0: return True diff --git a/tests/http/testenv/caddy.py b/tests/http/testenv/caddy.py index 6d79559b7e..14f71f5bfd 100644 --- a/tests/http/testenv/caddy.py +++ b/tests/http/testenv/caddy.py @@ -27,9 +27,9 @@ import os import socket import subprocess import time -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone from json import JSONEncoder -from typing import Dict +from typing import ClassVar, Dict from .curl import CurlClient from .env import Env @@ -40,7 +40,7 @@ log = logging.getLogger(__name__) class Caddy: - PORT_SPECS = { + PORT_SPECS: ClassVar[Dict[str, int]] = { 'caddy': socket.SOCK_STREAM, 'caddys': socket.SOCK_STREAM, } @@ -137,8 +137,8 @@ class Caddy: def wait_dead(self, timeout: timedelta): curl = CurlClient(env=self.env, run_dir=self._tmp_dir) - try_until = datetime.now() + timeout - while datetime.now() < try_until: + try_until = datetime.now(timezone.utc) + timeout + while datetime.now(timezone.utc) < try_until: check_url = f'https://{self.env.domain1}:{self.port}/' r = curl.http_get(url=check_url) if r.exit_code != 0: @@ -150,8 +150,8 @@ class Caddy: def wait_live(self, timeout: timedelta): curl = CurlClient(env=self.env, run_dir=self._tmp_dir) - try_until = datetime.now() + timeout - while datetime.now() < try_until: + try_until = datetime.now(timezone.utc) + timeout + while datetime.now(timezone.utc) < try_until: check_url = f'https://{self.env.domain1}:{self.port}/' r = curl.http_get(url=check_url) if r.exit_code == 0: diff --git a/tests/http/testenv/certs.py b/tests/http/testenv/certs.py index 6376a3d445..ab87bfa49e 100644 --- a/tests/http/testenv/certs.py +++ b/tests/http/testenv/certs.py @@ -350,7 +350,7 @@ class CertStore: (cert.not_valid_before_utc > now)): return None except AttributeError: # older python - now = datetime.now() + now = datetime.now(timezone.utc) if check_valid and \ ((cert.not_valid_after < now) or (cert.not_valid_before > now)): @@ -422,10 +422,10 @@ class TestCA: pubkey = pkey.public_key() issuer_subject = issuer_subject if issuer_subject is not None else subject - valid_from = datetime.now() + valid_from = datetime.now(timezone.utc) if valid_until_delta is not None: valid_from += valid_from_delta - valid_until = datetime.now() + valid_until = datetime.now(timezone.utc) if valid_until_delta is not None: valid_until += valid_until_delta diff --git a/tests/http/testenv/client.py b/tests/http/testenv/client.py index a2e72237f4..c851246fe8 100644 --- a/tests/http/testenv/client.py +++ b/tests/http/testenv/client.py @@ -26,7 +26,7 @@ import logging import os import shutil import subprocess -from datetime import datetime +from datetime import datetime, timezone from typing import Dict, Optional from . import ExecResult @@ -81,7 +81,7 @@ class LocalClient: def run(self, args): self._rmf(self._stdoutfile) self._rmf(self._stderrfile) - start = datetime.now() + start = datetime.now(timezone.utc) exception = None myargs = [self.path, self.name] myargs.extend(args) @@ -107,7 +107,7 @@ class LocalClient: cerrput = ferr.readlines() return ExecResult(args=myargs, exit_code=exitcode, exception=exception, stdout=coutput, stderr=cerrput, - duration=datetime.now() - start) + duration=datetime.now(timezone.utc) - start) def dump_logs(self): lines = [] diff --git a/tests/http/testenv/curl.py b/tests/http/testenv/curl.py index 7b026e325f..64b089ba81 100644 --- a/tests/http/testenv/curl.py +++ b/tests/http/testenv/curl.py @@ -35,7 +35,7 @@ from datetime import datetime, timedelta, timezone from functools import cmp_to_key from statistics import fmean, mean from threading import Thread -from typing import Any, Dict, List, Optional, Tuple, Union +from typing import Any, ClassVar, Dict, List, Optional, Tuple, Union from urllib.parse import urlparse import psutil @@ -47,7 +47,7 @@ log = logging.getLogger(__name__) class RunProfile: - STAT_KEYS = ['cpu', 'rss', 'vsz'] + STAT_KEYS: ClassVar[List[str]] = ['cpu', 'rss', 'vsz'] @classmethod def AverageStats(cls, profiles: List['RunProfile']): @@ -76,7 +76,7 @@ class RunProfile: return self._stats def sample(self): - elapsed = datetime.now() - self._started_at + elapsed = datetime.now(timezone.utc) - self._started_at try: if self._psu is None: self._psu = psutil.Process(pid=self._pid) @@ -92,7 +92,7 @@ class RunProfile: pass def finish(self): - self._duration = datetime.now() - self._started_at + self._duration = datetime.now(timezone.utc) - self._started_at if len(self._samples) > 0: weights = [s['time'].total_seconds() for s in self._samples] self._stats = {} @@ -605,7 +605,7 @@ class ExecResult: class CurlClient: - ALPN_ARG = { + ALPN_ARG: ClassVar[Dict[str, str]] = { 'http/0.9': '--http0.9', 'http/1.0': '--http1.0', 'http/1.1': '--http1.1', @@ -1028,7 +1028,7 @@ class CurlClient: if with_tcpdump: tcpdump = RunTcpDump(self.env, self._run_dir) tcpdump.start() - started_at = datetime.now() + started_at = datetime.now(timezone.utc) try: with open(self._stdoutfile, 'w') as cout, open(self._stderrfile, 'w') as cerr: if with_profile: @@ -1051,7 +1051,7 @@ class CurlClient: p.wait(timeout=ptimeout) break except subprocess.TimeoutExpired as e: - if end_at and datetime.now() >= end_at: + if end_at and datetime.now(timezone.utc) >= end_at: p.kill() raise subprocess.TimeoutExpired(cmd=args, timeout=self._timeout) from e profile.sample() @@ -1067,13 +1067,13 @@ class CurlClient: env=self._run_env, check=False) exitcode = p.returncode except subprocess.TimeoutExpired: - now = datetime.now() + now = datetime.now(timezone.utc) duration = now - started_at log.warning(f'Timeout at {now} after {duration.total_seconds()}s ' f'(configured {self._timeout}s): {args}') exitcode = -1 exception = 'TimeoutExpired' - ended_at = datetime.now() + ended_at = datetime.now(timezone.utc) if tcpdump: tcpdump.finish() if perf: diff --git a/tests/http/testenv/dante.py b/tests/http/testenv/dante.py index 43b058e196..f42e3f8755 100644 --- a/tests/http/testenv/dante.py +++ b/tests/http/testenv/dante.py @@ -27,7 +27,7 @@ import os import socket import subprocess import time -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone from typing import Dict from . import CurlClient @@ -137,8 +137,8 @@ class Dante: timeout=timeout.total_seconds(), socks_args=[ '--socks5', f'127.0.0.1:{self._port}' ]) - try_until = datetime.now() + timeout - while datetime.now() < try_until: + try_until = datetime.now(timezone.utc) + timeout + while datetime.now(timezone.utc) < try_until: r = curl.http_get(url=f'http://{self.env.domain1}:{self.env.http_port}/') if r.exit_code == 0: return True diff --git a/tests/http/testenv/dnsd.py b/tests/http/testenv/dnsd.py index 18cfafcc38..d80405e9e8 100644 --- a/tests/http/testenv/dnsd.py +++ b/tests/http/testenv/dnsd.py @@ -27,7 +27,7 @@ import os import socket import subprocess import time -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone from typing import Dict, List, Optional from .env import Env @@ -133,8 +133,8 @@ class Dnsd: return self.wait_live(timeout=timedelta(seconds=Env.SERVER_TIMEOUT)) def wait_live(self, timeout: timedelta): - try_until = datetime.now() + timeout - while datetime.now() < try_until: + try_until = datetime.now(timezone.utc) + timeout + while datetime.now(timezone.utc) < try_until: if os.path.exists(self._log_file): return True time.sleep(.1) diff --git a/tests/http/testenv/h2o.py b/tests/http/testenv/h2o.py index f36e6975ce..b7008b3c3c 100644 --- a/tests/http/testenv/h2o.py +++ b/tests/http/testenv/h2o.py @@ -28,8 +28,8 @@ import signal import socket import subprocess import time -from datetime import datetime, timedelta -from typing import Dict, Optional +from datetime import datetime, timedelta, timezone +from typing import ClassVar, Dict, Optional from .curl import CurlClient from .env import Env @@ -181,12 +181,12 @@ class H2o: running = self._process self._process = None os.kill(running.pid, signal.SIGQUIT) - end_wait = datetime.now() + timedelta(seconds=5) + end_wait = datetime.now(timezone.utc) + timedelta(seconds=5) exited = False if not self.start(wait_live=False): self._process = running return False - while datetime.now() < end_wait: + while datetime.now(timezone.utc) < end_wait: try: self._log("debug", f"waiting for h2o({running.pid}) to exit.") running.wait(1) @@ -199,7 +199,7 @@ class H2o: except subprocess.TimeoutExpired: self._log("warning", f"h2o({running.pid}), not shut down yet.") os.kill(running.pid, signal.SIGQUIT) - if not exited and datetime.now() >= end_wait: + if not exited and datetime.now(timezone.utc) >= end_wait: self._log("error", f"h2o({running.pid}), terminate forcefully.") os.kill(running.pid, signal.SIGKILL) running.terminate() @@ -215,10 +215,10 @@ class H2o: log_prefix: str = "h2o", ): curl = CurlClient(env=self.env, run_dir=self._tmp_dir) - try_until = datetime.now() + timeout + try_until = datetime.now(timezone.utc) + timeout if url is None: url = f"https://{self._domain}:{self._port}/" - while datetime.now() < try_until: + while datetime.now(timezone.utc) < try_until: if live: r = curl.http_get( url=url, extra_args=["--trace", "curl.trace", "--trace-time"] @@ -245,7 +245,7 @@ class H2o: class H2oServer(H2o): """h2o HTTP/3 server for testing.""" - PORT_SPECS = { + PORT_SPECS: ClassVar[Dict[str, int]] = { "h2o_https": socket.SOCK_STREAM, } @@ -422,10 +422,10 @@ error-log: {self._error_log} log_prefix: str = "h2o", ): curl = CurlClient(env=self.env, run_dir=self._tmp_dir) - try_until = datetime.now() + timeout + try_until = datetime.now(timezone.utc) + timeout if url is None: url = f"https://{self.env.proxy_domain}:{self._port}/" - while datetime.now() < try_until: + while datetime.now(timezone.utc) < try_until: if live: r = curl.http_get( url=url, extra_args=["--trace", "curl.trace", "--trace-time"] diff --git a/tests/http/testenv/httpd.py b/tests/http/testenv/httpd.py index c389a9a56c..8ef53395ff 100644 --- a/tests/http/testenv/httpd.py +++ b/tests/http/testenv/httpd.py @@ -31,9 +31,9 @@ import socket import subprocess import textwrap import time -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone from json import JSONEncoder -from typing import Dict, List, Optional, Union +from typing import ClassVar, Dict, List, Optional, Union from .curl import CurlClient, ExecResult from .env import Env, EnvError @@ -44,7 +44,7 @@ log = logging.getLogger(__name__) class Httpd: - MODULES = [ + MODULES: ClassVar[List[str]] = [ 'log_config', 'logio', 'unixd', 'version', 'watchdog', 'authn_core', 'authn_file', 'authz_user', 'authz_core', 'authz_host', @@ -55,14 +55,14 @@ class Httpd: 'brotli', 'mpm_event', ] - COMMON_MODULES_DIRS = [ + COMMON_MODULES_DIRS: ClassVar[List[str]] = [ '/usr/lib/apache2/modules', # debian '/usr/libexec/apache2/', # macos ] MOD_CURLTEST = None - PORT_SPECS = { + PORT_SPECS: ClassVar[Dict[str, int]] = { 'http': socket.SOCK_STREAM, 'https': socket.SOCK_STREAM, 'https-tcp-only': socket.SOCK_STREAM, @@ -141,11 +141,11 @@ class Httpd: p = subprocess.run(args, capture_output=True, cwd=self.env.gen_dir, input=intext.encode() if intext else None, env=env, check=True) - start = datetime.now() + start = datetime.now(timezone.utc) return ExecResult(args=args, exit_code=p.returncode, stdout=p.stdout.decode().splitlines(), stderr=p.stderr.decode().splitlines(), - duration=datetime.now() - start) + duration=datetime.now(timezone.utc) - start) def _cmd_httpd(self, cmd: str): args = [self.env.httpd, @@ -221,8 +221,8 @@ class Httpd: def wait_dead(self, timeout: timedelta): curl = CurlClient(env=self.env, run_dir=self._tmp_dir) - try_until = datetime.now() + timeout - while datetime.now() < try_until: + try_until = datetime.now(timezone.utc) + timeout + while datetime.now(timezone.utc) < try_until: r = curl.http_get(url=f'http://{self.env.domain1}:{self.ports["http"]}/') if r.exit_code != 0: self._maybe_running = False @@ -234,8 +234,8 @@ class Httpd: def wait_live(self, timeout: timedelta): curl = CurlClient(env=self.env, run_dir=self._tmp_dir, timeout=timeout.total_seconds()) - try_until = datetime.now() + timeout - while datetime.now() < try_until: + try_until = datetime.now(timezone.utc) + timeout + while datetime.now(timezone.utc) < try_until: r = curl.http_get(url=f'http://{self.env.domain1}:{self.ports["http"]}/') if r.exit_code == 0: self._maybe_running = True diff --git a/tests/http/testenv/nghttpx.py b/tests/http/testenv/nghttpx.py index 50dd5e2152..ba0cbe1a79 100644 --- a/tests/http/testenv/nghttpx.py +++ b/tests/http/testenv/nghttpx.py @@ -29,8 +29,8 @@ import socket import subprocess import textwrap import time -from datetime import datetime, timedelta -from typing import Dict, Optional +from datetime import datetime, timedelta, timezone +from typing import ClassVar, Dict, Optional from .curl import CurlClient from .env import Env, NghttpxUtil @@ -135,11 +135,11 @@ class Nghttpx: running = self._process self._process = None os.kill(running.pid, signal.SIGQUIT) - end_wait = datetime.now() + timedelta(seconds=5) + end_wait = datetime.now(timezone.utc) + timedelta(seconds=5) if not self.start(wait_live=False): self._process = running return False - while datetime.now() < end_wait: + while datetime.now(timezone.utc) < end_wait: try: log.debug(f'waiting for nghttpx({running.pid}) to exit.') running.wait(1) @@ -149,7 +149,7 @@ class Nghttpx: except subprocess.TimeoutExpired: log.warning(f'nghttpx({running.pid}), not shut down yet.') os.kill(running.pid, signal.SIGQUIT) - if running and datetime.now() >= end_wait: + if running and datetime.now(timezone.utc) >= end_wait: log.error(f'nghttpx({running.pid}), terminate forcefully.') os.kill(running.pid, signal.SIGKILL) running.terminate() @@ -159,8 +159,8 @@ class Nghttpx: def wait_dead(self, timeout: timedelta): curl = CurlClient(env=self.env, run_dir=self._tmp_dir) - try_until = datetime.now() + timeout - while datetime.now() < try_until: + try_until = datetime.now(timezone.utc) + timeout + while datetime.now(timezone.utc) < try_until: xargs = [ '--trace', 'curl.trace', '--trace-time', '--connect-timeout', '1' @@ -178,8 +178,8 @@ class Nghttpx: def wait_live(self, timeout: timedelta): curl = CurlClient(env=self.env, run_dir=self._tmp_dir) - try_until = datetime.now() + timeout - while datetime.now() < try_until: + try_until = datetime.now(timezone.utc) + timeout + while datetime.now(timezone.utc) < try_until: xargs = [ '--trace', 'curl.trace', '--trace-time', '--connect-timeout', '1' @@ -212,7 +212,7 @@ class Nghttpx: class NghttpxQuic(Nghttpx): - PORT_SPECS = { + PORT_SPECS: ClassVar[Dict[str, int]] = { 'nghttpx_https': socket.SOCK_STREAM, } @@ -327,8 +327,8 @@ class NghttpxFwd(Nghttpx): def wait_dead(self, timeout: timedelta): curl = CurlClient(env=self.env, run_dir=self._tmp_dir) - try_until = datetime.now() + timeout - while datetime.now() < try_until: + try_until = datetime.now(timezone.utc) + timeout + while datetime.now(timezone.utc) < try_until: check_url = f'https://{self.env.proxy_domain}:{self._port}/' r = curl.http_get(url=check_url) if r.exit_code != 0: @@ -340,8 +340,8 @@ class NghttpxFwd(Nghttpx): def wait_live(self, timeout: timedelta): curl = CurlClient(env=self.env, run_dir=self._tmp_dir) - try_until = datetime.now() + timeout - while datetime.now() < try_until: + try_until = datetime.now(timezone.utc) + timeout + while datetime.now(timezone.utc) < try_until: check_url = f'https://{self.env.proxy_domain}:{self._port}/' r = curl.http_get(url=check_url, extra_args=[ '--trace', 'curl.trace', '--trace-time' diff --git a/tests/http/testenv/sshd.py b/tests/http/testenv/sshd.py index 57c7d1e34a..7753e855c9 100644 --- a/tests/http/testenv/sshd.py +++ b/tests/http/testenv/sshd.py @@ -28,7 +28,7 @@ import socket import stat import subprocess import time -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone from typing import Dict from . import CurlClient @@ -242,8 +242,8 @@ class Sshd: def wait_live(self, timeout: timedelta): curl = CurlClient(env=self.env, run_dir=self._tmp_dir, timeout=timeout.total_seconds()) - try_until = datetime.now() + timeout - while datetime.now() < try_until: + try_until = datetime.now(timezone.utc) + timeout + while datetime.now(timezone.utc) < try_until: r = curl.http_get(url=f'scp://{self.env.domain1}:{self._port}/{self.home_dir}/data', extra_args=[ '--insecure', diff --git a/tests/http/testenv/vsftpd.py b/tests/http/testenv/vsftpd.py index 7cd9596b16..cda57b1822 100644 --- a/tests/http/testenv/vsftpd.py +++ b/tests/http/testenv/vsftpd.py @@ -28,7 +28,7 @@ import re import socket import subprocess import time -from datetime import datetime, timedelta +from datetime import datetime, timedelta, timezone from typing import Dict, List, Tuple from .curl import CurlClient, ExecResult @@ -152,8 +152,8 @@ class VsFTPD: def wait_dead(self, timeout: timedelta): curl = CurlClient(env=self.env, run_dir=self._tmp_dir) - try_until = datetime.now() + timeout - while datetime.now() < try_until: + try_until = datetime.now(timezone.utc) + timeout + while datetime.now(timezone.utc) < try_until: check_url = f'{self._scheme}://{self.domain}:{self.port}/' r = curl.ftp_get(urls=[check_url], extra_args=['-v']) if r.exit_code != 0: @@ -165,8 +165,8 @@ class VsFTPD: def wait_live(self, timeout: timedelta): curl = CurlClient(env=self.env, run_dir=self._tmp_dir) - try_until = datetime.now() + timeout - while datetime.now() < try_until: + try_until = datetime.now(timezone.utc) + timeout + while datetime.now(timezone.utc) < try_until: check_url = f'{self._scheme}://{self.domain}:{self.port}/' r = curl.ftp_get(urls=[check_url], extra_args=[ '--trace', 'curl-start.trace', '--trace-time' From 3de2777421b25f8bc1dcd115143c3e1b5ae9f15a Mon Sep 17 00:00:00 2001 From: Dan Fandrich Date: Sat, 25 Jul 2026 13:34:38 -0700 Subject: [PATCH 12/15] tests: target Python 3.8 as the minimum Python version This version is already two releases out of support, but is "only" 7 years old so is probably still being used in the real world. Document this version along with some other testing dependencies. Remove code support for earlier versions. Disable ruff checks that need a newer version. --- docs/INTERNALS.md | 13 +++++++++++++ scripts/pythonlint.sh | 6 ++++-- tests/dictserver.py | 2 -- tests/http/testenv/ports.py | 3 +-- tests/negtelnetserver.py | 9 +-------- 5 files changed, 19 insertions(+), 14 deletions(-) diff --git a/docs/INTERNALS.md b/docs/INTERNALS.md index 244d7c46c3..77d17e83a0 100644 --- a/docs/INTERNALS.md +++ b/docs/INTERNALS.md @@ -64,6 +64,19 @@ these or later versions: - perl 5.8 (2002-07-19), on Windows: 5.22 (2015-06-01) - Visual Studio 2010 10.0 (2010-04-12 - 2020-07-14) +## Testing + +Certain tests require the following packages to operate. In some cases, tests +that do not find the necessary requirements are automatically skipped. + +- OpenSSL (see above) +- nghttp2 (see above) +- OpenSSH +- perl (see above) +- pytest +- Python 3.8 (2019-10-14) +- stunnel + ## Library Symbols All symbols used internally in libcurl must use a `Curl_` prefix if they are diff --git a/scripts/pythonlint.sh b/scripts/pythonlint.sh index a6d6aa2dd4..1385533064 100755 --- a/scripts/pythonlint.sh +++ b/scripts/pythonlint.sh @@ -29,9 +29,11 @@ set -eu -ruff check --extend-select=B007,B016,C405,C416,COM818,D200,D213,D204,D401,\ +ruff check --target-version=py38 \ +--extend-select=B007,B016,C405,C416,COM818,D200,D213,D204,D401,\ D415,FURB129,N818,PERF401,PERF403,PIE790,PIE808,PLW0127,Q004,RUF010,SIM101,\ SIM117,SIM118,TRY400,TRY401,RET503,RET504,UP004,B018,B904,RSE102,RET505,I001 \ +--ignore=FA100 \ "$@" # Checks that are in preview only, since --preview otherwise turns them all on -ruff check --preview --select=E301,E302,E303,E304,E305,E306,E502 "$@" +ruff check --target-version=py38 --preview --select=E301,E302,E303,E304,E305,E306,E502 "$@" diff --git a/tests/dictserver.py b/tests/dictserver.py index 87a00d61d0..bff6e80157 100755 --- a/tests/dictserver.py +++ b/tests/dictserver.py @@ -25,8 +25,6 @@ # """DICT server.""" -from __future__ import absolute_import, division, print_function, unicode_literals - import argparse import logging import os diff --git a/tests/http/testenv/ports.py b/tests/http/testenv/ports.py index 2436d40767..8f25daedca 100644 --- a/tests/http/testenv/ports.py +++ b/tests/http/testenv/ports.py @@ -25,8 +25,7 @@ import logging import os import socket -from collections.abc import Callable -from typing import Dict +from typing import Callable, Dict from filelock import FileLock diff --git a/tests/negtelnetserver.py b/tests/negtelnetserver.py index ad7cb53e98..8d074f5046 100755 --- a/tests/negtelnetserver.py +++ b/tests/negtelnetserver.py @@ -22,22 +22,15 @@ # """A telnet server which negotiates.""" -from __future__ import absolute_import, division, print_function, unicode_literals - import argparse import logging import os import socket +import socketserver import sys from util import ClosingFileHandler -if sys.version_info.major >= 3: - import socketserver -else: - import SocketServer as socketserver - - log = logging.getLogger(__name__) HOST = "localhost" IDENT = "NTEL" From 5e75aedab2214c6114f1ad52b1bce6a6cd302480 Mon Sep 17 00:00:00 2001 From: Dan Fandrich Date: Sat, 25 Jul 2026 16:41:05 -0700 Subject: [PATCH 13/15] tests: bump ruff version to 0.60.0 This version enables many more warnings by default. Closes #22396 --- .github/scripts/requirements.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/scripts/requirements.txt b/.github/scripts/requirements.txt index 8d1a74af04..d068818e57 100644 --- a/.github/scripts/requirements.txt +++ b/.github/scripts/requirements.txt @@ -5,4 +5,4 @@ cmakelang==0.6.13 codespell==2.4.3 reuse==6.2.0 -ruff==0.15.16 +ruff==0.16.0 From 75404bda1a4fe062fdb5c98b31c0be2e1558674e Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Tue, 28 Jul 2026 17:08:02 +0200 Subject: [PATCH 14/15] curl_gssapi: document/update feature availability - update `GSS_C_DELEG_POLICY_FLAG` comment to include Apple GSS, add date, and amend MIT Kerberos version to 1.7+ (was: 1.8+) Ref: https://github.com/krb5/krb5/commit/45875a4d7bbd6bb8a943572d84fef5ca2bb18291 Ref: https://github.com/apple-oss-distributions/Heimdal/commit/1635de38a813f6e1dd3f8fd270683187ad4f02be - document `HAVE_GSS_SET_NEG_MECHS`/`gss_set_neg_mechs()`. Ref: https://github.com/krb5/krb5/commit/079eed2cf749702f75ddc385cf943fbab931f9d8 It's also committed to Heimdal, but not present in a release as of 7.8.0 (current latest). Ref: https://github.com/heimdal/heimdal/commit/735039dbdc3aa58d06afdefd214efe3f5e421244 Follow-up to a8881e5e1d2e22d4b085d45ab6c8ce1df251d602 #21315 #22410 Follow-up to d169ad68faa5ed5ba2375e7502307a6262466d88 #22052 Closes #22419 --- lib/curl_gssapi.c | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/lib/curl_gssapi.c b/lib/curl_gssapi.c index ccc24e09b1..354fa00dea 100644 --- a/lib/curl_gssapi.c +++ b/lib/curl_gssapi.c @@ -435,7 +435,8 @@ static OM_uint32 stub_gss_indicate_mechs( return GSS_S_COMPLETE; } -#ifdef HAVE_GSS_SET_NEG_MECHS +#ifdef HAVE_GSS_SET_NEG_MECHS /* MIT Kerberos 1.8+ (2010-03-02), + missing from Apple GSS, GNU GSS */ static OM_uint32 stub_gss_set_neg_mechs( OM_uint32 *min, gss_cred_id_t cred_handle, @@ -509,7 +510,8 @@ OM_uint32 Curl_gss_init_sec_context(struct Curl_easy *data, req_flags |= GSS_C_MUTUAL_FLAG; if(data->set.gssapi_delegation & CURLGSSAPI_DELEGATION_POLICY_FLAG) { -#ifdef GSS_C_DELEG_POLICY_FLAG /* MIT Kerberos 1.8+, missing from GNU GSS */ +#ifdef GSS_C_DELEG_POLICY_FLAG /* MIT Kerberos 1.7+ (2009-06-02), Apple GSS, + missing from GNU GSS */ req_flags |= GSS_C_DELEG_POLICY_FLAG; #else infof(data, "WARNING: support for CURLGSSAPI_DELEGATION_POLICY_FLAG not " From 1386135d1c65a3d32c2887a60e66b41afef341ec Mon Sep 17 00:00:00 2001 From: Viktor Szakats Date: Wed, 15 Jul 2026 18:04:59 +0200 Subject: [PATCH 15/15] schannel: fix error check logic in `get_client_cert()` file reader Reported by GitHub Code Quality Follow-up to 0fdf96512613574591f501d63fe49495ba40e1d5 #5193 Closes #22415 --- lib/vtls/schannel.c | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/lib/vtls/schannel.c b/lib/vtls/schannel.c index f55784c624..583c87222d 100644 --- a/lib/vtls/schannel.c +++ b/lib/vtls/schannel.c @@ -441,12 +441,13 @@ static CURLcode get_client_cert(struct Curl_cfilter *cf, if(fInCert) { long cert_tell = 0; bool continue_reading = fseek(fInCert, 0, SEEK_END) == 0; - if(continue_reading) + if(continue_reading) { cert_tell = ftell(fInCert); - if(cert_tell < 0) - continue_reading = FALSE; - else - certsize = (size_t)cert_tell; + if(cert_tell < 0) + continue_reading = FALSE; + else + certsize = (size_t)cert_tell; + } if(continue_reading) continue_reading = fseek(fInCert, 0, SEEK_SET) == 0; if(continue_reading && (certsize < CURL_MAX_INPUT_LENGTH))