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 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/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/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 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/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/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/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/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/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/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..354fa00dea 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,175 @@ 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 /* 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, + 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 +501,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; @@ -326,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 " @@ -340,7 +525,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 +540,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 +568,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_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/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/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 63a40784a8..a7c1fe8c83 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)); @@ -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/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/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/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/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) 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/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/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..583c87222d 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; @@ -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)) @@ -2736,7 +2737,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 +2786,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 +2829,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 +2838,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/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/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/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 9d23b98470..f28a66d929 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/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/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/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/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/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/dictserver.py b/tests/dictserver.py index b4e1afd78b..bff6e80157 100755 --- a/tests/dictserver.py +++ b/tests/dictserver.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | @@ -26,8 +25,6 @@ # """DICT server.""" -from __future__ import absolute_import, division, print_function, unicode_literals - import argparse import logging import os @@ -97,12 +94,12 @@ 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")) - 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/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 5bc24cf2c9..41682ae132 --- a/tests/http/scorecard.py +++ b/tests/http/scorecard.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- #*************************************************************************** # _ _ ____ _ # Project ___| | | | _ \| | @@ -148,7 +147,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 @@ -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}') @@ -263,7 +262,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 +273,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): @@ -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"]) @@ -794,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() @@ -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..940245920d 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" @@ -703,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_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 76c12bc8e5..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 ___| | | | _ \| | @@ -24,6 +22,7 @@ # ########################################################################### # +import contextlib import logging import os import socket @@ -192,13 +191,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_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 774a7737c9..9321d71414 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 ___| | | | _ \| | @@ -70,21 +68,19 @@ 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("""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() - except ConnectionAbortedError: - self._done = True - except OSError: + except (ConnectionAbortedError, OSError): self._done = True 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..5d59765b69 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 ___| | | | _ \| | @@ -28,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 @@ -35,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, @@ -51,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, @@ -82,9 +83,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 \ @@ -222,7 +222,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 { @@ -267,9 +267,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 [] @@ -319,13 +319,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] @@ -521,7 +520,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..b559383c93 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 ___| | | | _ \| | @@ -34,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 @@ -61,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 @@ -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 1d554b1906..14f71f5bfd 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 ___| | | | _ \| | @@ -29,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 @@ -42,14 +40,14 @@ log = logging.getLogger(__name__) class Caddy: - PORT_SPECS = { + PORT_SPECS: ClassVar[Dict[str, int]] = { 'caddy': socket.SOCK_STREAM, 'caddys': socket.SOCK_STREAM, } 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') @@ -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 @@ -125,7 +123,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() @@ -139,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: @@ -152,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 85012634a5..ab87bfa49e 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 ___| | | | _ \| | @@ -57,6 +55,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 +152,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 +251,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)) @@ -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: @@ -353,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)): @@ -389,20 +386,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 Exception(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: @@ -427,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 76c4822cbc..c851246fe8 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 ___| | | | _ \| | @@ -28,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 @@ -41,13 +39,13 @@ 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 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' @@ -83,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) @@ -98,7 +96,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}') @@ -109,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 2abbbbe49c..64b089ba81 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 ___| | | | _ \| | @@ -24,6 +22,7 @@ # ########################################################################### # +import contextlib import json import logging import os @@ -36,19 +35,19 @@ 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 -from .env import Env +from .env import Env, EnvError 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']): @@ -73,11 +72,11 @@ 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): - 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) @@ -93,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 = {} @@ -133,12 +132,8 @@ class PerfProfile: self._proc.terminate() self._rc = self._proc.returncode with open(self._file, 'w') as cout: - p = 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}') + subprocess.run(['sudo', 'perf', 'script'], + stdout=cout, cwd=self._run_dir, shell=False, check=True) @property def file(self): @@ -192,7 +187,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 +217,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 +227,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 +244,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') @@ -500,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}' @@ -606,13 +599,13 @@ 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: - ALPN_ARG = { + ALPN_ARG: ClassVar[Dict[str, str]] = { 'http/0.9': '--http0.9', 'http/1.0': '--http1.0', 'http/1.1': '--http1.1', @@ -634,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' @@ -649,13 +642,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 @@ -857,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: @@ -886,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([ @@ -919,7 +912,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 +988,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' @@ -1035,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: @@ -1058,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() @@ -1071,16 +1064,16 @@ 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() + 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: @@ -1160,7 +1153,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': @@ -1168,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]) @@ -1243,36 +1236,28 @@ 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([ - 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}') + 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): 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([ - 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}') + 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], @@ -1281,7 +1266,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 +1277,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 +1288,9 @@ class CurlClient: title = cmdline subtitle = '' with open(file_svg, 'w') as cout, open(file_err, 'a') as cerr: - p = 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}') + 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..f42e3f8755 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 ___| | | | _ \| | @@ -29,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 @@ -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,10 +135,10 @@ 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}' - ]) - try_until = datetime.now() + timeout - while datetime.now() < try_until: + '--socks5', f'127.0.0.1:{self._port}' + ]) + 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 8f6bb3edc8..d80405e9e8 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 ___| | | | _ \| | @@ -29,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 @@ -128,15 +126,15 @@ 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 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/env.py b/tests/http/testenv/env.py index 8f619271a2..0c19d6bd16 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 ___| | | | _ \| | @@ -43,6 +41,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 +60,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 +79,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 +129,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 +158,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 +220,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 +250,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 +268,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 +288,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 +309,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 +328,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 +346,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 +367,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}") @@ -516,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: @@ -540,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 @@ -917,14 +912,13 @@ 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") + 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 - 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..b7008b3c3c 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 ___| | | | _ \| | @@ -30,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 @@ -97,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): @@ -108,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}") @@ -133,7 +129,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 @@ -185,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) @@ -203,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() @@ -219,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"] @@ -249,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, } @@ -426,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 64ca796d13..8ef53395ff 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 ___| | | | _ \| | @@ -31,13 +29,14 @@ import os import shutil 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 +from .env import Env, EnvError from .ports import alloc_ports_and_do log = logging.getLogger(__name__) @@ -45,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', @@ -56,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, @@ -95,14 +94,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) @@ -141,15 +138,14 @@ 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) - start = datetime.now() + env=env, check=True) + 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, @@ -174,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() @@ -225,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 @@ -238,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 @@ -483,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: @@ -585,11 +580,10 @@ 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) + 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}") - 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/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/http/testenv/nghttpx.py b/tests/http/testenv/nghttpx.py index 37c72ad945..ba0cbe1a79 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 ___| | | | _ \| | @@ -29,9 +27,10 @@ import os import signal 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 @@ -136,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) @@ -150,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() @@ -160,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' @@ -179,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' @@ -205,15 +204,15 @@ 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): - PORT_SPECS = { + PORT_SPECS: ClassVar[Dict[str, int]] = { 'nghttpx_https': socket.SOCK_STREAM, } @@ -270,7 +269,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 +319,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 @@ -328,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: @@ -341,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/ports.py b/tests/http/testenv/ports.py index f3d2348fa6..8f25daedca 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 ___| | | | _ \| | @@ -27,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 @@ -39,13 +36,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..7753e855c9 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 ___| | | | _ \| | @@ -30,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 @@ -125,11 +123,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 +135,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 +146,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: @@ -241,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 @@ -250,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 e2c33edee3..cda57b1822 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 ___| | | | _ \| | @@ -30,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 @@ -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 @@ -154,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: @@ -167,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' 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 f3f659a27f..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 ___| | | | _ \| | @@ -26,6 +25,7 @@ # import argparse import asyncio +import contextlib import logging from websockets import server @@ -33,12 +33,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/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 0b20780b7e..fafdd8de99 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}, @@ -2261,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; @@ -2315,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/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 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/negtelnetserver.py b/tests/negtelnetserver.py index a9a4880018..8d074f5046 100755 --- a/tests/negtelnetserver.py +++ b/tests/negtelnetserver.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- # # Project ___| | | | _ \| | # / __| | | | |_) | | @@ -23,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" @@ -109,8 +101,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: @@ -311,9 +303,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/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/smbserver.py b/tests/smbserver.py index 44daefc15a..1072fd239d 100755 --- a/tests/smbserver.py +++ b/tests/smbserver.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- # # Project ___| | | | _ \| | # / __| | | | |_) | | @@ -65,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() @@ -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) @@ -292,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) @@ -352,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 @@ -372,9 +371,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/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); diff --git a/tests/util.py b/tests/util.py index 7db47d0a00..7c0ad4b499 100755 --- a/tests/util.py +++ b/tests/util.py @@ -1,5 +1,4 @@ #!/usr/bin/env python3 -# -*- coding: utf-8 -*- # # Project ___| | | | _ \| | # / __| | | | |_) | | @@ -34,30 +33,30 @@ 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: - 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 @@ -67,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) @@ -77,7 +75,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() 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 +}